wangxinhui
2026-02-27 804051e9e3013a3ad6b3e47757050e32893cf4fb
WCS堆垛机流程
已添加11个文件
已重命名1个文件
已删除71个文件
已修改19个文件
23619 ■■■■■ 文件已修改
.vs/FengLvLiTiKu/v17/.wsuo 补丁 | 查看 | 原始文档 | blame | 历史
.vs/VSWorkspaceState.json 7 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
代码管理/BigScreen/.gitignore 21 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
代码管理/BigScreen/LICENSE 201 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
代码管理/BigScreen/README.md 200 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
代码管理/BigScreen/babel.config.js 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
代码管理/BigScreen/package-lock.json 15274 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
代码管理/BigScreen/package.json 65 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
代码管理/BigScreen/public/favicon.ico 补丁 | 查看 | 原始文档 | blame | 历史
代码管理/BigScreen/public/image.png 补丁 | 查看 | 原始文档 | blame | 历史
代码管理/BigScreen/public/index.html 18 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
代码管理/BigScreen/src/App.vue 14 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
代码管理/BigScreen/src/api/ajax.js 58 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
代码管理/BigScreen/src/api/http.js 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
代码管理/BigScreen/src/assets/FZ.png 补丁 | 查看 | 原始文档 | blame | 历史
代码管理/BigScreen/src/assets/JX.png 补丁 | 查看 | 原始文档 | blame | 历史
代码管理/BigScreen/src/assets/LB.png 补丁 | 查看 | 原始文档 | blame | 历史
代码管理/BigScreen/src/assets/SC.jpg 补丁 | 查看 | 原始文档 | blame | 历史
代码管理/BigScreen/src/assets/benterblue.png 补丁 | 查看 | 原始文档 | blame | 历史
代码管理/BigScreen/src/assets/bg5.jpg 补丁 | 查看 | 原始文档 | blame | 历史
代码管理/BigScreen/src/assets/blue.png 补丁 | 查看 | 原始文档 | blame | 历史
代码管理/BigScreen/src/assets/cnmc_logo.png 补丁 | 查看 | 原始文档 | blame | 历史
代码管理/BigScreen/src/assets/head_bg1.png 补丁 | 查看 | 原始文档 | blame | 历史
代码管理/BigScreen/src/assets/logo.png 补丁 | 查看 | 原始文档 | blame | 历史
代码管理/BigScreen/src/assets/pageBg.png 补丁 | 查看 | 原始文档 | blame | 历史
代码管理/BigScreen/src/assets/red0.png 补丁 | 查看 | 原始文档 | blame | 历史
代码管理/BigScreen/src/assets/red1.png 补丁 | 查看 | 原始文档 | blame | 历史
代码管理/BigScreen/src/assets/scss/_variables.scss 98 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
代码管理/BigScreen/src/assets/scss/index.scss 138 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
代码管理/BigScreen/src/assets/scss/style.scss 185 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
代码管理/BigScreen/src/assets/yellow.png 补丁 | 查看 | 原始文档 | blame | 历史
代码管理/BigScreen/src/common/echart/index.vue 66 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
代码管理/BigScreen/src/common/echart/theme.json 490 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
代码管理/BigScreen/src/common/map/fujian.js 48 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
代码管理/BigScreen/src/components/echart/bottom/bottomCenterChart/chart.vue 184 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
代码管理/BigScreen/src/components/echart/bottom/bottomCenterChart/index.vue 58 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
代码管理/BigScreen/src/components/echart/bottom/bottomLeftChart/chart.vue 187 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
代码管理/BigScreen/src/components/echart/bottom/bottomLeftChart/index.vue 66 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
代码管理/BigScreen/src/components/echart/bottom/bottomRightChart/chart.vue 358 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
代码管理/BigScreen/src/components/echart/bottom/bottomRightChart/index.vue 90 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
代码管理/BigScreen/src/components/echart/center/centerChartRate/index.vue 104 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
代码管理/BigScreen/src/components/echart/centerLeft/centerLeft1Chart/chart.vue 65 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
代码管理/BigScreen/src/components/echart/centerLeft/centerLeft1Chart/index.vue 88 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
代码管理/BigScreen/src/components/echart/centerLeft/centerLeft2Chat/chart.vue 65 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
代码管理/BigScreen/src/components/echart/centerLeft/centerLeft2Chat/index.vue 88 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
代码管理/BigScreen/src/components/echart/centerLeft/centerLeft3Chart/chart.vue 76 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
代码管理/BigScreen/src/components/echart/centerLeft/centerLeft3Chart/index.vue 38 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
代码管理/BigScreen/src/main.js 37 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
代码管理/BigScreen/src/router/index.js 21 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
代码管理/BigScreen/src/store/index.js 15 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
代码管理/BigScreen/src/utils/drawMixin.js 57 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
代码管理/BigScreen/src/utils/index.js 51 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
代码管理/BigScreen/src/utils/resizeMixin.js 32 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
代码管理/BigScreen/src/views/bottomView1.vue 138 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
代码管理/BigScreen/src/views/centerView1.vue 505 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
代码管理/BigScreen/src/views/index.vue 333 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
代码管理/BigScreen/src/views/indexLine.vue 283 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
代码管理/BigScreen/src/views/indexPick.vue 389 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
代码管理/BigScreen/vue.config.js 16 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
代码管理/WCS/WCSServers/WIDESEAWCS_Common/TaskEnum/StackerCommandEnum.cs 68 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
代码管理/WCS/WCSServers/WIDESEAWCS_Common/TaskEnum/TaskEnumHelper.cs 21 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
代码管理/WCS/WCSServers/WIDESEAWCS_Common/TaskEnum/TaskStatusEnum.cs 176 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
代码管理/WCS/WCSServers/WIDESEAWCS_ITaskInfoService/ITaskService.cs 62 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
代码管理/WCS/WCSServers/WIDESEAWCS_Model/Models/BasicInfo/Dt_ApiInfo.cs 44 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
代码管理/WCS/WCSServers/WIDESEAWCS_Model/Models/BasicInfo/Dt_StationManger.cs 96 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
代码管理/WCS/WCSServers/WIDESEAWCS_Model/WIDESEAWCS_Model.csproj 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
代码管理/WCS/WCSServers/WIDESEAWCS_QuartzJob/QuartzNet/QuartzNetExtension.cs 102 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
代码管理/WCS/WCSServers/WIDESEAWCS_QuartzJob/Robot/StackerCraneDevice.cs 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
代码管理/WCS/WCSServers/WIDESEAWCS_QuartzJob/Service/DispatchInfoService.cs 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
代码管理/WCS/WCSServers/WIDESEAWCS_Server/Controllers/BasicInfo/RouterController.cs 5 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
代码管理/WCS/WCSServers/WIDESEAWCS_Server/Controllers/System/Sys_DictionaryController.cs 51 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
代码管理/WCS/WCSServers/WIDESEAWCS_Server/Filter/CustomProfile.cs 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
代码管理/WCS/WCSServers/WIDESEAWCS_Server/appsettings.json 15 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
代码管理/WCS/WCSServers/WIDESEAWCS_TaskInfoService/TaskExecuteDetailService.cs 124 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
代码管理/WCS/WCSServers/WIDESEAWCS_TaskInfoService/TaskService.cs 212 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
代码管理/WCS/WCSServers/WIDESEAWCS_Tasks/ConveyorLineJob/CommonConveyorLineJob.cs 210 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
代码管理/WCS/WCSServers/WIDESEAWCS_Tasks/ConveyorLineJob/ConveyorLineDBName.cs 40 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
代码管理/WCS/WCSServers/WIDESEAWCS_Tasks/ConveyorLineJob/ConveyorLineTaskCommand.cs 38 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
代码管理/WCS/WCSServers/WIDESEAWCS_Tasks/FormationStackerCraneJob/FormationCommonStackerCraneJob.cs 308 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
代码管理/WCS/WCSServers/WIDESEAWCS_Tasks/FormationStackerCraneJob/FormationStackerCraneDBName.cs 84 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
代码管理/WCS/WCSServers/WIDESEAWCS_Tasks/FormationStackerCraneJob/FormationStackerCraneTaskCommand.cs 97 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
代码管理/WCS/WCSServers/WIDESEAWCS_Tasks/RobotJob/RobotJob.cs 297 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
代码管理/WCS/WCSServers/WIDESEAWCS_Tasks/SerialPortJob.cs 128 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
代码管理/WCS/WCSServers/WIDESEAWCS_Tasks/ShuttleCarJob/ShuttleCarJob.cs 47 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
代码管理/WCS/WCSServers/WIDESEAWCS_Tasks/SocketServer/SocketServerOptions.cs 12 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
代码管理/WCS/WCSServers/WIDESEAWCS_Tasks/SocketServer/TcpSocketServer.Clients.cs 54 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
代码管理/WCS/WCSServers/WIDESEAWCS_Tasks/SocketServer/TcpSocketServer.Dispose.cs 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
代码管理/WCS/WCSServers/WIDESEAWCS_Tasks/SocketServer/TcpSocketServer.Messaging.cs 131 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
代码管理/WCS/WCSServers/WIDESEAWCS_Tasks/SocketServer/TcpSocketServer.Server.cs 41 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
代码管理/WCS/WCSServers/WIDESEAWCS_Tasks/SocketServer/TcpSocketServer.cs 64 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
代码管理/WCS/WCSServers/WIDESEAWCS_Tasks/StackerCraneJob/CommonStackerCraneJob.cs 313 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
代码管理/WCS/WCSServers/WIDESEAWCS_Tasks/StackerCraneJob/StackerCraneDBName.cs 80 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
代码管理/WCS/WCSServers/WIDESEAWCS_Tasks/StackerCraneJob/StackerCraneJob.cs 206 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
代码管理/WCS/WCSServers/WIDESEAWCS_Tasks/StackerCraneJob/StackerCraneTaskCommand.cs 83 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
代码管理/WCS/WCSServers/WIDESEAWCS_Tasks/TestJob.cs 74 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
代码管理/WCS/WCSServices/WIDESEAWCS_Server/Controllers/Task/TaskController.cs 88 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目资料/通讯协议/SIS报文格式报文样例V1.6(带备注).xlsx 补丁 | 查看 | 原始文档 | blame | 历史
项目资料/通讯协议/基础通讯中译协议.pdf 补丁 | 查看 | 原始文档 | blame | 历史
项目资料/通讯协议/堆垛机通讯中译协议.pdf 补丁 | 查看 | 原始文档 | blame | 历史
项目资料/通讯协议/输送线通讯中译协议.pdf 补丁 | 查看 | 原始文档 | blame | 历史
项目资料/部署环境及软件开发简介/net6.zip 补丁 | 查看 | 原始文档 | blame | 历史
项目资料/部署环境及软件开发简介/软件开发培训.pptx 补丁 | 查看 | 原始文档 | blame | 历史
.vs/FengLvLiTiKu/v17/.wsuo
Binary files differ
.vs/VSWorkspaceState.json
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,7 @@
{
  "ExpandedNodes": [
    ""
  ],
  "SelectedNode": "\\WIDESEA_WMSServer.sln",
  "PreviewInSolutionExplorer": false
}
´úÂë¹ÜÀí/BigScreen/.gitignore
ÎļþÒÑɾ³ý
´úÂë¹ÜÀí/BigScreen/LICENSE
ÎļþÒÑɾ³ý
´úÂë¹ÜÀí/BigScreen/README.md
ÎļþÒÑɾ³ý
´úÂë¹ÜÀí/BigScreen/babel.config.js
ÎļþÒÑɾ³ý
´úÂë¹ÜÀí/BigScreen/package-lock.json
ÎļþÒÑɾ³ý
´úÂë¹ÜÀí/BigScreen/package.json
ÎļþÒÑɾ³ý
´úÂë¹ÜÀí/BigScreen/public/favicon.ico
Binary files differ
´úÂë¹ÜÀí/BigScreen/public/image.png
Binary files differ
´úÂë¹ÜÀí/BigScreen/public/index.html
ÎļþÒÑɾ³ý
´úÂë¹ÜÀí/BigScreen/src/App.vue
ÎļþÒÑɾ³ý
´úÂë¹ÜÀí/BigScreen/src/api/ajax.js
ÎļþÒÑɾ³ý
´úÂë¹ÜÀí/BigScreen/src/api/http.js
ÎļþÒÑɾ³ý
´úÂë¹ÜÀí/BigScreen/src/assets/FZ.png
Binary files differ
´úÂë¹ÜÀí/BigScreen/src/assets/JX.png
Binary files differ
´úÂë¹ÜÀí/BigScreen/src/assets/LB.png
Binary files differ
´úÂë¹ÜÀí/BigScreen/src/assets/SC.jpg
Binary files differ
´úÂë¹ÜÀí/BigScreen/src/assets/benterblue.png
Binary files differ
´úÂë¹ÜÀí/BigScreen/src/assets/bg5.jpg
Binary files differ
´úÂë¹ÜÀí/BigScreen/src/assets/blue.png
Binary files differ
´úÂë¹ÜÀí/BigScreen/src/assets/cnmc_logo.png
Binary files differ
´úÂë¹ÜÀí/BigScreen/src/assets/head_bg1.png
Binary files differ
´úÂë¹ÜÀí/BigScreen/src/assets/logo.png
Binary files differ
´úÂë¹ÜÀí/BigScreen/src/assets/pageBg.png
Binary files differ
´úÂë¹ÜÀí/BigScreen/src/assets/red0.png
Binary files differ
´úÂë¹ÜÀí/BigScreen/src/assets/red1.png
Binary files differ
´úÂë¹ÜÀí/BigScreen/src/assets/scss/_variables.scss
ÎļþÒÑɾ³ý
´úÂë¹ÜÀí/BigScreen/src/assets/scss/index.scss
ÎļþÒÑɾ³ý
´úÂë¹ÜÀí/BigScreen/src/assets/scss/style.scss
ÎļþÒÑɾ³ý
´úÂë¹ÜÀí/BigScreen/src/assets/yellow.png
Binary files differ
´úÂë¹ÜÀí/BigScreen/src/common/echart/index.vue
ÎļþÒÑɾ³ý
´úÂë¹ÜÀí/BigScreen/src/common/echart/theme.json
ÎļþÒÑɾ³ý
´úÂë¹ÜÀí/BigScreen/src/common/map/fujian.js
ÎļþÒÑɾ³ý
´úÂë¹ÜÀí/BigScreen/src/components/echart/bottom/bottomCenterChart/chart.vue
ÎļþÒÑɾ³ý
´úÂë¹ÜÀí/BigScreen/src/components/echart/bottom/bottomCenterChart/index.vue
ÎļþÒÑɾ³ý
´úÂë¹ÜÀí/BigScreen/src/components/echart/bottom/bottomLeftChart/chart.vue
ÎļþÒÑɾ³ý
´úÂë¹ÜÀí/BigScreen/src/components/echart/bottom/bottomLeftChart/index.vue
ÎļþÒÑɾ³ý
´úÂë¹ÜÀí/BigScreen/src/components/echart/bottom/bottomRightChart/chart.vue
ÎļþÒÑɾ³ý
´úÂë¹ÜÀí/BigScreen/src/components/echart/bottom/bottomRightChart/index.vue
ÎļþÒÑɾ³ý
´úÂë¹ÜÀí/BigScreen/src/components/echart/center/centerChartRate/index.vue
ÎļþÒÑɾ³ý
´úÂë¹ÜÀí/BigScreen/src/components/echart/centerLeft/centerLeft1Chart/chart.vue
ÎļþÒÑɾ³ý
´úÂë¹ÜÀí/BigScreen/src/components/echart/centerLeft/centerLeft1Chart/index.vue
ÎļþÒÑɾ³ý
´úÂë¹ÜÀí/BigScreen/src/components/echart/centerLeft/centerLeft2Chat/chart.vue
ÎļþÒÑɾ³ý
´úÂë¹ÜÀí/BigScreen/src/components/echart/centerLeft/centerLeft2Chat/index.vue
ÎļþÒÑɾ³ý
´úÂë¹ÜÀí/BigScreen/src/components/echart/centerLeft/centerLeft3Chart/chart.vue
ÎļþÒÑɾ³ý
´úÂë¹ÜÀí/BigScreen/src/components/echart/centerLeft/centerLeft3Chart/index.vue
ÎļþÒÑɾ³ý
´úÂë¹ÜÀí/BigScreen/src/main.js
ÎļþÒÑɾ³ý
´úÂë¹ÜÀí/BigScreen/src/router/index.js
ÎļþÒÑɾ³ý
´úÂë¹ÜÀí/BigScreen/src/store/index.js
ÎļþÒÑɾ³ý
´úÂë¹ÜÀí/BigScreen/src/utils/drawMixin.js
ÎļþÒÑɾ³ý
´úÂë¹ÜÀí/BigScreen/src/utils/index.js
ÎļþÒÑɾ³ý
´úÂë¹ÜÀí/BigScreen/src/utils/resizeMixin.js
ÎļþÒÑɾ³ý
´úÂë¹ÜÀí/BigScreen/src/views/bottomView1.vue
ÎļþÒÑɾ³ý
´úÂë¹ÜÀí/BigScreen/src/views/centerView1.vue
ÎļþÒÑɾ³ý
´úÂë¹ÜÀí/BigScreen/src/views/index.vue
ÎļþÒÑɾ³ý
´úÂë¹ÜÀí/BigScreen/src/views/indexLine.vue
ÎļþÒÑɾ³ý
´úÂë¹ÜÀí/BigScreen/src/views/indexPick.vue
ÎļþÒÑɾ³ý
´úÂë¹ÜÀí/BigScreen/vue.config.js
ÎļþÒÑɾ³ý
´úÂë¹ÜÀí/WCS/WCSServers/WIDESEAWCS_Common/TaskEnum/StackerCommandEnum.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,68 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace WIDESEAWCS_Common.TaskEnum
{
    /// <summary>
    /// ä¸Žå †åž›äº¤äº’报文
    /// </summary>
    public enum StackerCommandEnum
    {
        /// <summary>
        /// å‘送给堆垛机任务
        /// </summary>
        ARQ,
        /// <summary>
        /// å›žå¤éœ€è¦ç¡®è®¤çš„æŠ¥æ–‡<br/>
        /// æ”¶åˆ°å¯¹æ–¹æŠ¥æ–‡ä»¥åŽæ˜¯å¦éœ€è¦å›žå¤ACK<br/>
        /// å–决于元素报文结构中的元素2<br/>
        /// å¦‚果为1,需回复ACK<br/>
        /// å¦‚果为0,不回复ACK<br/>
        /// </summary>
        ACK,
        /// <summary>
        /// å †åž›æœºç»™åˆ°WCS的报文<br/>
        /// ä»»åŠ¡æ‰§è¡Œå®Œæˆ<br/>
        /// ä»»åŠ¡æ— æ³•æ‰§è¡Œ<br/>
        /// ä»»åŠ¡åˆ é™¤ã€ç­‰åŽŸå› <br/>
        /// </summary>
        ACP,
        /// <summary>
        /// è¿”回给发送者,接收者接收到的报文不正确或者接收者无法正确处理该报文
        /// </summary>
        NCK,
        /// <summary>
        /// å‘送给堆垛机,请求初始化序列号
        /// </summary>
        SYN,
        /// <summary>
        /// å¿ƒè·³æ£€æµ‹,询问对方是否仍在线
        /// </summary>
        DUM,
        /// <summary>
        /// å¿ƒè·³å›žå¤
        /// </summary>
        DUA,
        /// <summary>
        /// WCS发送给堆垛机,请求删除任务
        /// </summary>
        DER,
        /// <summary>
        /// å †åž›æœºå›žå¤WCS的DER报文,任务删除/无法删除
        /// </summary>
        DEC,
        /// <summary>
        /// WCS发给堆垛机,请求当前堆垛机的状态
        /// </summary>
        CRQ,
        /// <summary>
        /// å †åž›æœºå‘ç»™WCS,报告堆垛机当前的状态<br/>
        /// å½“堆垛机状态发生改变将会发送一个CSR<br/>
        /// å †åž›æœºæ²¡ä»»åŠ¡ï¼Œå›žå¤çš„ä»»åŠ¡å·æ˜¯00000000
        /// </summary>
        CSR
    }
}
´úÂë¹ÜÀí/WCS/WCSServers/WIDESEAWCS_Common/TaskEnum/TaskEnumHelper.cs
@@ -41,11 +41,6 @@
            {
                return TaskTypeGroup.RelocationGroup;
            }
            // å°è¯•将任务类型转换为TaskOtherTypeEnum枚举类型,如果成功,返回OtherGroup
            else if (!int.TryParse(Enum.Parse<TaskOtherTypeEnum>(taskTypeStr).ToString(), out result))
            {
                return TaskTypeGroup.OtherGroup;
            }
            // å¦‚果以上转换都不成功,抛出NotImplementedException异常
            else
            {
@@ -63,24 +58,12 @@
            // å¦‚æžœtype不是枚举类型,返回0
            if (!type.IsEnum) return 0;
            // å¦‚æžœtype是TaskInStatusEnum枚举类型
            if (type == typeof(TaskInStatusEnum))
            if (type == typeof(TaskStatusEnum))
            {
                // èŽ·å–TaskInStatusEnum枚举类型的索引列表
                List<int> taskInboundTypes = type.GetEnumIndexList();
                // è¿”回大于当前状态且小于InFinish状态的索引
                return taskInboundTypes.Where(x => x > currentStatus && x < (int)TaskInStatusEnum.InFinish).OrderBy(x => x).FirstOrDefault();
            }
            // å¦‚æžœtype是TaskOutStatusEnum枚举类型
            else if (type == typeof(TaskOutStatusEnum))
            {
                // èŽ·å–TaskOutStatusEnum枚举类型的索引列表
                return type.GetEnumIndexList().Where(x => x > currentStatus && x < (int)TaskOutStatusEnum.OutFinish).OrderBy(x => x).FirstOrDefault();
            }
            // å¦‚æžœtype是TaskRobotStatusEnum枚举类型
            else if (type == typeof(TaskRobotStatusEnum))
            {
                // èŽ·å–TaskOutStatusEnum枚举类型的索引列表
                return type.GetEnumIndexList().Where(x => x > currentStatus && x < (int)TaskRobotStatusEnum.RobotFinish).OrderBy(x => x).FirstOrDefault();
                return taskInboundTypes.Where(x => x > currentStatus).OrderBy(x => x).FirstOrDefault();
            }
            // å¦‚果以上条件都不满足,抛出NotImplementedException异常
            else
´úÂë¹ÜÀí/WCS/WCSServers/WIDESEAWCS_Common/TaskEnum/TaskStatusEnum.cs
@@ -7,180 +7,84 @@
namespace WIDESEAWCS_Common.TaskEnum
{
    public enum TaskInStatusEnum
    public enum TaskStatusEnum
    {
        /// <summary>
        /// æ–°å»ºå…¥åº“任务
        /// æ–°å»ºä»»åŠ¡
        /// </summary>
        [Description("新建入库任务")]
        InNew = 200,
        ///// <summary>
        ///// AGV入库执行中
        ///// </summary>
        //[Description("AGV入库执行中")]
        //AGV_InExecuting = 210,
        ///// <summary>
        ///// AGV入库完成
        ///// </summary>
        //[Description("AGV搬运完成")]
        //AGV_InFinish = 215,
        [Description("新建")]
        New = 100,
        /// <summary>
        /// è¾“送线入库执行中
        /// å †åž›æœºå¾…执行
        /// </summary>
        [Description("输送线入库执行中")]
        Line_InExecuting = 220,
        [Description("堆垛机待执行")]
        SC_Execute = 200,
        /// <summary>
        /// è¾“送线入库完成
        /// å †åž›æœºç­‰å¾…确认中
        /// </summary>
        [Description("输送线输送完成")]
        Line_InFinish = 225,
        [Description("堆垛机等待确认中")]
        SC_Waiting = 205,
        /// <summary>
        /// å †åž›æœºå…¥åº“执行中
        /// å †åž›æœºæ‰§è¡Œä¸­
        /// </summary>
        [Description("堆垛机入库执行中")]
        SC_InExecuting = 230,
        [Description("堆垛机执行中")]
        SC_Executing = 210,
        /// <summary>
        /// å †åž›æœºå…¥åº“完成
        /// å †åž›æœºå®Œæˆ
        /// </summary>
        [Description("堆垛机入库完成")]
        SC_InFinish = 235,
        [Description("堆垛机完成")]
        SC_Finish = 220,
        /// <summary>
        /// å…¥åº“任务完成
        /// è¾“送线待执行
        /// </summary>
        [Description("入库任务完成")]
        InFinish = 290,
        [Description("输送线待执行")]
        Line_Execute = 400,
        /// <summary>
        /// å…¥åº“任务挂起
        /// è¾“送线等待确认中
        /// </summary>
        [Description("入库任务挂起")]
        InPending = 297,
        [Description("输送线等待确认中")]
        Line_Waiting = 405,
        /// <summary>
        /// å…¥åº“任务取消
        /// è¾“送线执行中
        /// </summary>
        [Description("入库任务取消")]
        InCancel = 298,
        [Description("输送线执行中")]
        Line_Executing = 410,
        /// <summary>
        /// å…¥åº“任务异常
        /// è¾“送线完成
        /// </summary>
        [Description("入库任务异常")]
        InException = 299,
    }
    public enum TaskOutStatusEnum
    {
        /// <summary>
        /// æ–°å»ºå‡ºåº“任务
        /// </summary>
        [Description("新建出库任务")]
        OutNew = 100,
        [Description("输送线完成")]
        Line_Finish = 420,
        /// <summary>
        /// å †åž›æœºå‡ºåº“执行中
        /// ä»»åŠ¡å®Œæˆ
        /// </summary>
        [Description("堆垛机出库执行中")]
        SC_OutExecuting = 110,
        [Description("任务完成")]
        Finish = 900,
        /// <summary>
        /// å †åž›æœºå‡ºåº“完成
        /// ä»»åŠ¡æŒ‚èµ·
        /// </summary>
        [Description("堆垛机出库完成")]
        SC_OutFinish = 115,
        [Description("任务挂起")]
        Pending = 970,
        /// <summary>
        /// è¾“送线出库执行中
        /// ä»»åŠ¡å–æ¶ˆ
        /// </summary>
        [Description("输送线出库执行中")]
        Line_OutExecuting = 120,
        [Description("任务取消")]
        Cancel = 980,
        /// <summary>
        /// è¾“送线出库完成
        /// ä»»åС异叏
        /// </summary>
        [Description("输送线输送完成")]
        Line_OutFinish = 125,
        ///// <summary>
        ///// AGV出库执行中
        ///// </summary>
        //[Description("AGV出库执行中")]
        //AGV_OutExecuting = 130,
        ///// <summary>
        ///// AGV出库完成
        ///// </summary>
        //[Description("AGV搬运完成")]
        //AGV_OutFinish = 135,
        /// <summary>
        /// å‡ºåº“任务完成
        /// </summary>
        [Description("出库任务完成")]
        OutFinish = 190,
        /// <summary>
        /// å‡ºåº“任务挂起
        /// </summary>
        [Description("出库任务挂起")]
        OutPending = 197,
        /// <summary>
        /// å‡ºåº“任务取消
        /// </summary>
        [Description("出库任务取消")]
        OutCancel = 198,
        /// <summary>
        /// å‡ºåº“任务异常
        /// </summary>
        [Description("出库任务异常")]
        OutException = 199,
    }
    public enum TaskRobotStatusEnum
    {
        /// <summary>
        /// æœºæ¢°æ‰‹æ–°å»ºä»»åŠ¡
        /// </summary>
        [Description("机械手新建任务")]
        RobotNew = 300,
        /// <summary>
        /// æœºæ¢°æ‰‹æ‰§è¡Œä¸­
        /// </summary>
        [Description("机械手执行中")]
        RobotExecuting = 310,
        /// <summary>
        /// æœºæ¢°æ‰‹å®Œæˆ
        /// </summary>
        [Description("机械手完成")]
        RobotFinish = 390,
        /// <summary>
        /// æœºæ¢°æ‰‹ä»»åŠ¡æŒ‚èµ·
        /// </summary>
        [Description("机械手任务挂起")]
        RobotPending = 397,
        /// <summary>
        /// æœºæ¢°æ‰‹ä»»åŠ¡å–æ¶ˆ
        /// </summary>
        [Description("机械手任务取消")]
        RobotCancel = 398,
        /// <summary>
        /// æœºæ¢°æ‰‹ä»»åС异叏
        /// </summary>
        [Description("机械手任务异常")]
        RobotException = 399,
        [Description("任务异常")]
        Exception = 990
    }
}
´úÂë¹ÜÀí/WCS/WCSServers/WIDESEAWCS_ITaskInfoService/ITaskService.cs
@@ -49,11 +49,6 @@
        public List<int> TaskOutboundTypes {  get; }
        /// <summary>
        /// æ‰€æœ‰å‡ºåº“任务类型
        /// </summary>
        public List<int> TaskRobotTypes { get; }
        /// <summary>
        /// æŽ¥æ”¶WMS任务信息
        /// </summary>
        /// <param name="taskDTOs">WMS任务对象集合</param>
@@ -83,63 +78,6 @@
        /// <param name="nextAddress">下一地址</param>
        /// <returns></returns>
        Dt_Task QueryExecutingConveyorLineTask(int taskNum, string nextAddress);
        /// <summary>
        /// æ ¹æ®ä»»åŠ¡å·ã€å½“å‰åœ°å€æŸ¥è¯¢è¾“é€çº¿å®Œæˆçš„ä»»åŠ¡
        /// </summary>
        /// <param name="taskNum">任务号</param>
        /// <param name="currentAddress">当前地址</param>
        /// <returns></returns>
        Dt_Task QueryCompletedConveyorLineTask(int taskNum, string currentAddress);
        /// <summary>
        /// æ ¹æ®è®¾å¤‡ç¼–号、任务类型分组(可选)按照优先级以及创建时间排序查询任务池新增的任务
        /// </summary>
        /// <param name="deviceNo">设备编号</param>
        /// <param name="taskTypeGroup">任务类型分组(可选)</param>
        /// <returns></returns>
        Dt_Task? QuertStackerCraneTask(string deviceNo, TaskTypeGroup? taskTypeGroup = null);
        /// <summary>
        /// æ ¹æ®è®¾å¤‡ç¼–号、当前地址按照优先级以及创建时间排序查询任务池新增的任务
        /// </summary>
        /// <param name="deviceNo">设备编号</param>
        /// <param name="currentAddress">当前地址</param>
        /// <returns>返回任务实体对象,可能为null</returns>
        Dt_Task QueryStackerCraneTask(string deviceNo, string currentAddress = "");
        /// <summary>
        /// æ ¹æ®è®¾å¤‡ç¼–号、当前地址按照优先级以及创建时间排序查询任务池新增的任务
        /// </summary>
        /// <param name="deviceNo">设备编号</param>
        /// <param name="currentAddress">当前地址</param>
        /// <returns>返回任务实体对象,可能为null</returns>
        Dt_Task QueryRobotCraneTask(string deviceNo,string currentAddress = "");
        /// <summary>
        /// æ ¹æ®è®¾å¤‡ç¼–号、当前地址按照优先级以及创建时间排序查询任务池入库类型的新增的任务
        /// </summary>
        /// <param name="deviceNo">设备编号</param>
        /// <param name="currentAddress">当前地址</param>
        /// <returns>返回任务实体对象,可能为null</returns>
        Dt_Task QueryStackerCraneInTask(string deviceNo, string currentAddress = "");
        /// <summary>
        /// æ ¹æ®è®¾å¤‡ç¼–号、当前地址按照优先级以及创建时间排序查询任务池出库类型的新增的任务
        /// </summary>
        /// <param name="deviceNo">设备编号</param>
        /// <param name="currentAddress">当前地址</param>
        /// <returns>返回任务实体对象,可能为null</returns>
        Dt_Task QueryStackerCraneOutTask(string deviceNo, string currentAddress = "");
        /// <summary>
        /// æ ¹æ®è®¾å¤‡ç¼–号、当前地址按照优先级以及创建时间排序查询任务池出库类型的新增的任务
        /// </summary>
        /// <param name="deviceNo">设备编号</param>
        /// <param name="outStationCodes">当前地址</param>
        /// <returns>返回任务实体对象集合,可能为null</returns>
        List<Dt_Task> QueryStackerCraneOutTasks(string deviceNo, List<string> outStationCodes);
        /// <summary>
        /// æ›´æ–°ä»»åŠ¡å¼‚å¸¸ä¿¡æ¯æ˜¾ç¤º
´úÂë¹ÜÀí/WCS/WCSServers/WIDESEAWCS_Model/Models/BasicInfo/Dt_ApiInfo.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,44 @@
using SqlSugar;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using WIDESEAWCS_Core.DB.Models;
namespace WIDESEAWCS_Model.Models
{
    [SugarTable(nameof(Dt_ApiInfo), "接口信息")]
    public class Dt_ApiInfo : BaseEntity
    {
        /// <summary>
        /// ä¸»é”®
        /// </summary>
        [SugarColumn(IsPrimaryKey = true, IsIdentity = true, ColumnDescription = "主键")]
        public int Id { get; set; }
        /// <summary>
        /// æŽ¥å£ç¼–号
        /// </summary>
        [SugarColumn(IsNullable = false, Length = 50, ColumnDescription = "接口编号")]
        public string ApiCode { get; set; }
        /// <summary>
        /// æŽ¥å£åç§°
        /// </summary>
        [SugarColumn(IsNullable = true, Length = 50, ColumnDescription = "接口名称")]
        public string ApiName { get; set; }
        /// <summary>
        /// æŽ¥å£åœ°å€
        /// </summary>
        [SugarColumn(IsNullable = false, Length = 200, ColumnDescription = "接口地址")]
        public string ApiAddress { get; set; }
        /// <summary>
        /// å¤‡æ³¨
        /// </summary>
        [SugarColumn(IsNullable = true, Length = 50, ColumnDescription = "备注")]
        public string Remark { get; set; }
    }
}
´úÂë¹ÜÀí/WCS/WCSServers/WIDESEAWCS_Model/Models/BasicInfo/Dt_StationManger.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,96 @@
using SqlSugar;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using WIDESEAWCS_Core.DB.Models;
namespace WIDESEAWCS_Model.Models
{
    [SugarTable(nameof(Dt_StationManger), "站台表")]
    public class Dt_StationManger : BaseEntity
    {
        /// <summary>
        /// ä¸»é”®
        /// </summary>
        [SugarColumn(IsPrimaryKey = true, IsIdentity = true, ColumnDescription = "主键")]
        public int Id { get; set; }
        /// <summary>
        /// ç«™å°ç¼–号
        /// </summary>
        [SugarColumn(IsNullable = false, Length = 50, ColumnDescription = "站台编号")]
        public string StationCode { get; set; }
        /// <summary>
        /// ç«™å°åç§°
        /// </summary>
        [SugarColumn(IsNullable = true, Length = 50, ColumnDescription = "站台名称")]
        public string StationName { get; set; }
        /// <summary>
        /// ç«™å°ç±»åž‹ <br/>
        /// 1:只入 <br/>
        /// 2:只出 <br/>
        /// 3:可入可出
        /// </summary>
        [SugarColumn(IsNullable = false, ColumnDescription = "站台类型")]
        public int StationType {  get; set; }
        /// <summary>
        /// å¯¹åº”堆垛机排-列-层
        /// </summary>
        [SugarColumn(IsNullable = false, Length = 50, ColumnDescription = "对应堆垛机排-列-层")]
        public string StackerCraneStationCode { get; set; }
        /// <summary>
        /// ç«™å°è®¾å¤‡ç¼–号
        /// </summary>
        [SugarColumn(IsNullable = false, Length = 50, ColumnDescription = "站台设备编号")]
        public string StationDeviceCode { get; set; }
        /// <summary>
        /// å †åž›æœºç¼–号
        /// </summary>
        [SugarColumn(IsNullable = false, Length = 50, ColumnDescription = "堆垛机编号")]
        public string StackerCraneCode { get; set; }
        /// <summary>
        /// AGV站台编号
        /// </summary>
        [SugarColumn(IsNullable = true, Length = 50, ColumnDescription = "AGV站台编号")]
        public string? AGVStationCode { get; set; }
        /// <summary>
        /// AGV站台取放高度
        /// </summary>
        [SugarColumn(IsNullable = true, ColumnDescription = "AGV站台取放高度")]
        public decimal AGVStationHeight { get; set; }
        /// <summary>
        /// AGV前置点
        /// </summary>
        [SugarColumn(IsNullable = true, Length = 50, ColumnDescription = "AGV前置点")]
        public string? AGVFrontCode { get; set; }
        /// <summary>
        /// ç«™å°æ˜¯å¦å¯ç”¨ <br/>
        /// 0:可用 <br/>
        /// 1:占用 <br/>
        /// </summary>
        [SugarColumn(IsNullable = false, ColumnDescription = "站台是否可用")]
        public int IsOccupied { get; set; }
        /// <summary>
        /// ç«™å°æ˜¯å¦å¯ç”¨ <br/>
        /// 0:可用 <br/>
        /// 1:占用 <br/>
        /// </summary>
        [SugarColumn(IsNullable = true, ColumnDescription = "站台是否可用")]
        public int IsManual { get; set; }
        /// <summary>
        /// å¤‡æ³¨
        /// </summary>
        [SugarColumn(IsNullable = true, Length = 50, ColumnDescription = "备注")]
        public string Remark { get; set; }
    }
}
´úÂë¹ÜÀí/WCS/WCSServers/WIDESEAWCS_Model/WIDESEAWCS_Model.csproj
@@ -16,8 +16,4 @@
        <ProjectReference Include="..\WIDESEAWCS_Core\WIDESEAWCS_Core.csproj" />
    </ItemGroup>
    <ItemGroup>
      <Folder Include="Models\BasicInfo\" />
    </ItemGroup>
</Project>
´úÂë¹ÜÀí/WCS/WCSServers/WIDESEAWCS_QuartzJob/QuartzNet/QuartzNetExtension.cs
@@ -2,6 +2,7 @@
using WIDESEAWCS_Core;
using WIDESEAWCS_Core.Helper;
using WIDESEAWCS_QuartzJob.DTO;
using WIDESEAWCS_QuartzJob.Models;
using WIDESEAWCS_QuartzJob.Service;
namespace WIDESEAWCS_QuartzJob.QuartzNet
@@ -41,95 +42,62 @@
                List<DispatchInfoDTO> dispatches = _dispatchInfoService.QueryDispatchInfos();
                List<DeviceInfoDTO> deviceInfos = await _deviceInfoService.QueryDeviceProInfos();
                deviceInfos.ForEach(x =>
                deviceInfos.ForEach(delegate (DeviceInfoDTO x)
                {
                    if (!Storage.Devices.Exists(d => d.DeviceCode == x.DeviceCode))
                    DeviceInfoDTO x2 = x;
                    if (!Storage.Devices.Exists((IDevice d) => d.DeviceCode == x2.DeviceCode) && !x.DeviceName.Contains("堆垛机"))
                    {
                        try
                        {
                            if (!x.DeviceName.Contains("堆垛机"))
                            Type type = Assembly.Load("WIDESEAWCS_Communicator").GetType("WIDESEAWCS_Communicator." + x2.DevicePlcType);
                            object obj = Activator.CreateInstance(type, x2.DeviceIp, x2.DevicePort, x2.DeviceName);
                            if (new bool?((bool)type.InvokeMember("Connect", BindingFlags.InvokeMethod, null, obj, new object[0])).GetValueOrDefault())
                            {
                                #region è¿žæŽ¥PLC
                                // åŠ è½½ç¨‹åºé›†
                                Assembly assembly = Assembly.Load($"WIDESEAWCS_Communicator");
                                // èŽ·å–ç±»åž‹
                                Type? type = assembly.GetType($"WIDESEAWCS_Communicator.{x.DevicePlcType}");
                                // åˆ›å»ºå®žä¾‹
                                object? obj = Activator.CreateInstance(type, new object[] { x.DeviceIp, x.DevicePort, x.DeviceName });
                                // è°ƒç”¨è¿žæŽ¥æ–¹æ³•
                                bool? connectResult = (bool)type.InvokeMember("Connect", BindingFlags.Default | BindingFlags.InvokeMethod, null, obj, new object[] { });
                                // åˆ¤æ–­è¿žæŽ¥ç»“æžœ
                                if (connectResult ?? false) ConsoleHelper.WriteSuccessLine(type.Name + x.DeviceCode + "连接成功"); else ConsoleHelper.WriteErrorLine(type.Name + x.DeviceCode + "连接失败");
                                #endregion è¿žæŽ¥PLC
                                #region å®žä¾‹åŒ–设备对象
                                List<DeviceProDTO> devicePros = x.ProtocolList.Select(d => new DeviceProDTO
                                {
                                    // è®¾å¤‡å­ç¼–码
                                    DeviceChildCode = d.DeviceChildCode,
                                    // è®¾å¤‡æ•°æ®ç±»åž‹
                                    DeviceDataType = d.DeviceProDataType,
                                    // è®¾å¤‡ID
                                    DeviceId = d.DeviceId,
                                    // è®¾å¤‡åè®®ID
                                    DeviceProId = d.Id,
                                    // è®¾å¤‡åè®®æ•°æ®å—
                                    DeviceProDataBlock = d.DeviceProDataBlock,
                                    // è®¾å¤‡åè®®æ•°æ®é•¿åº¦
                                    DeviceProDataLength = d.DeviceProDataLength,
                                    // è®¾å¤‡åè®®åç§»é‡
                                    DeviceProOffset = d.DeviceProOffset,
                                    // è®¾å¤‡åè®®å‚数描述
                                    DeviceProParamDes = d.DeviceProParamDes,
                                    // è®¾å¤‡åè®®å‚数名称
                                    DeviceProParamName = d.DeviceProParamName,
                                    // è®¾å¤‡åè®®å‚数类型
                                    DeviceProParamType = d.DeviceProParamType,
                                    // è®¾å¤‡PLC类型
                                    DevicePlcType = x.DevicePlcType
                                }).ToList();
                                // æ ¹æ®è®¾å¤‡ç±»åž‹èŽ·å–è®¾å¤‡åè®®è¯¦æƒ…
                                List<DeviceProtocolDetailDTO> deviceProtocolDetails = _deviceProtocolDetailService.GetDeviceProtocolDetailsByDeviceType(x.DeviceType);
                                // åŠ è½½è®¾å¤‡ç¨‹åºé›†
                                Assembly assemblyDevice = Assembly.Load($"WIDESEAWCS_QuartzJob");
                                // èŽ·å–è®¾å¤‡ç±»åž‹å¯¹åº”çš„ç±»åž‹
                                Type typeDevice = assemblyDevice.GetType($"WIDESEAWCS_QuartzJob.{x.DeviceType}");
                                // åˆ›å»ºè®¾å¤‡å®žä¾‹
                                object deviceInstance = Activator.CreateInstance(typeDevice, new object[] { obj, devicePros, deviceProtocolDetails, x.DeviceCode, x.DeviceName });
                                #endregion å®žä¾‹åŒ–设备对象
                                x.Device = (IDevice)deviceInstance;
                                Storage.Devices.Add((IDevice)deviceInstance);
                                (type.Name + x2.DeviceCode + "连接成功").WriteSuccessLine();
                            }
                            else
                            {
                                (type.Name + x2.DeviceCode + "连接失败").WriteErrorLine();
                            }
                            List<DeviceProDTO> list = x2.ProtocolList.Select((Dt_DeviceProtocol d) => new DeviceProDTO
                            {
                                DeviceChildCode = d.DeviceChildCode,
                                DeviceDataType = d.DeviceProDataType,
                                DeviceId = d.DeviceId,
                                DeviceProId = d.Id,
                                DeviceProDataBlock = d.DeviceProDataBlock,
                                DeviceProDataLength = d.DeviceProDataLength,
                                DeviceProOffset = d.DeviceProOffset,
                                DeviceProParamDes = d.DeviceProParamDes,
                                DeviceProParamName = d.DeviceProParamName,
                                DeviceProParamType = d.DeviceProParamType,
                                DevicePlcType = x2.DevicePlcType
                            }).ToList();
                            List<DeviceProtocolDetailDTO> deviceProtocolDetailsByDeviceType = _deviceProtocolDetailService.GetDeviceProtocolDetailsByDeviceType(x2.DeviceType);
                            object obj2 = Activator.CreateInstance(Assembly.Load("WIDESEAWCS_QuartzJob").GetType("WIDESEAWCS_QuartzJob." + x2.DeviceType), obj, list, deviceProtocolDetailsByDeviceType, x2.DeviceCode, x2.DeviceName);
                            x2.Device = (IDevice)obj2;
                            Storage.Devices.Add((IDevice)obj2);
                        }
                        catch (Exception ex)
                        catch (Exception ex2)
                        {
                            Console.WriteLine("调度服务开启异常" + ex.ToString());
                            Console.WriteLine("调度服务开启异常" + ex2.ToString());
                        }
                    }
                    else
                    {
                        x.Device = Storage.Devices.FirstOrDefault(d => d.DeviceCode == x.DeviceCode);
                        x2.Device = Storage.Devices.FirstOrDefault((IDevice d) => d.DeviceCode == x2.DeviceCode);
                    }
                });
                for (int i = 0; i < dispatches.Count; i++)
                {
                    var targetDevice = deviceInfos.FirstOrDefault(x => x.Id == dispatches[i].Id);
                    if (targetDevice is null) continue;
                    // ä½¿ç”¨æ¨¡å¼åŒ¹é…
                    dispatches[i].JobParams = targetDevice switch
                    {
                        { DeviceName: var name } when name.Contains("堆垛机")
                            => new RobotCraneDevice { DeviceCode = targetDevice.DeviceCode, DeviceName = targetDevice.DeviceName, IPAddress = targetDevice.DeviceIp + ":" + targetDevice.DevicePort },
                            => new StackerCraneDevice { DeviceCode = targetDevice.DeviceCode, DeviceName = targetDevice.DeviceName, IPAddress = targetDevice.DeviceIp + ":" + targetDevice.DevicePort },
                        _ => targetDevice.Device
                    };
                    WebResponseContent responseContent = await _schedulerCenter.AddScheduleJobAsync(dispatches[i]);
´úÂë¹ÜÀí/WCS/WCSServers/WIDESEAWCS_QuartzJob/Robot/StackerCraneDevice.cs
ÎļþÃû´Ó ´úÂë¹ÜÀí/WCS/WCSServers/WIDESEAWCS_QuartzJob/Robot/RobotCraneDevice.cs ÐÞ¸Ä
@@ -6,7 +6,7 @@
namespace WIDESEAWCS_QuartzJob
{
    public class RobotCraneDevice
    public class StackerCraneDevice
    {
        public string Device { get; set; }
        public string DeviceCode { get; set; }
´úÂë¹ÜÀí/WCS/WCSServers/WIDESEAWCS_QuartzJob/Service/DispatchInfoService.cs
@@ -64,7 +64,7 @@
                Creater = a.Creater,
                CycleHasRunTimes = 0,
                EndTime = a.EndTime,
                Id = a.Id,
                Id = b.Id,
                IntervalSecond = a.IntervalSecond,
                Modifier = a.Modifier,
                ModifyDate = a.ModifyDate,
´úÂë¹ÜÀí/WCS/WCSServers/WIDESEAWCS_Server/Controllers/BasicInfo/RouterController.cs
@@ -90,12 +90,9 @@
                #region èŽ·å–è®¾å¤‡ç¼–å·
                object deviceCodes = _deviceProtocolRepository.QueryData(x => true).GroupBy(x => x.DeviceChildCode).Select(x => new { key = x.Key, value = x.Key }).ToList();
                object areaInfos = Enum.GetNames(typeof(AreaInfo)).Select(x => new { key = x, value = x }).ToList();
                #endregion
                return WebResponseContent.Instance.OK(data: new { routerTypes, deviceCodes, areaInfos });
                return WebResponseContent.Instance.OK(data: new { routerTypes, deviceCodes});
            }
            catch (Exception ex)
            {
´úÂë¹ÜÀí/WCS/WCSServers/WIDESEAWCS_Server/Controllers/System/Sys_DictionaryController.cs
@@ -245,28 +245,6 @@
                            }
                            #endregion
                            #region TaskOtherTypeEnum
                            {
                                Type type = typeof(TaskOtherTypeEnum);
                                List<int> enums = Enum.GetValues(typeof(TaskOtherTypeEnum)).Cast<int>().ToList();
                                int index = 0;
                                foreach (var item in enums)
                                {
                                    FieldInfo? fieldInfo = typeof(TaskOtherTypeEnum).GetField(((TaskOtherTypeEnum)item).ToString());
                                    DescriptionAttribute? description = fieldInfo.GetCustomAttribute<DescriptionAttribute>();
                                    if (description != null)
                                    {
                                        data.Add(new { key = item.ToString(), value = description.Description });
                                    }
                                    else
                                    {
                                        data.Add(new { key = item.ToString(), value = item.ToString() });
                                    }
                                    index++;
                                }
                            }
                            #endregion
                            result = new VueDictionaryDTO { DicNo = key, Config = "", Data = data };
                        }
                        break;
@@ -276,12 +254,12 @@
                            #region TaskInStatusEnum
                            {
                                Type type = typeof(TaskInStatusEnum);
                                List<int> enums = Enum.GetValues(typeof(TaskInStatusEnum)).Cast<int>().ToList();
                                Type type = typeof(TaskStatusEnum);
                                List<int> enums = Enum.GetValues(typeof(TaskStatusEnum)).Cast<int>().ToList();
                                int index = 0;
                                foreach (var item in enums)
                                {
                                    FieldInfo? fieldInfo = typeof(TaskInStatusEnum).GetField(((TaskInStatusEnum)item).ToString());
                                    FieldInfo? fieldInfo = typeof(TaskStatusEnum).GetField(((TaskStatusEnum)item).ToString());
                                    DescriptionAttribute? description = fieldInfo.GetCustomAttribute<DescriptionAttribute>();
                                    if (description != null)
                                    {
@@ -295,29 +273,6 @@
                                }
                            }
                            #endregion
                            #region TaskOutStatusEnum
                            {
                                Type type = typeof(TaskOutStatusEnum);
                                List<int> enums = Enum.GetValues(typeof(TaskOutStatusEnum)).Cast<int>().ToList();
                                int index = 0;
                                foreach (var item in enums)
                                {
                                    FieldInfo? fieldInfo = typeof(TaskOutStatusEnum).GetField(((TaskOutStatusEnum)item).ToString());
                                    DescriptionAttribute? description = fieldInfo.GetCustomAttribute<DescriptionAttribute>();
                                    if (description != null)
                                    {
                                        data.Add(new { key = item.ToString(), value = description.Description });
                                    }
                                    else
                                    {
                                        data.Add(new { key = item.ToString(), value = item.ToString() });
                                    }
                                    index++;
                                }
                            }
                            #endregion
                            result = new VueDictionaryDTO { DicNo = key, Config = "", Data = data };
                        }
                        break;
´úÂë¹ÜÀí/WCS/WCSServers/WIDESEAWCS_Server/Filter/CustomProfile.cs
@@ -9,7 +9,6 @@
using WIDESEAWCS_Model.Models;
using WIDESEAWCS_QuartzJob.DTO;
using WIDESEAWCS_QuartzJob.Models;
using WIDESEAWCS_Tasks.ConveyorLineJob;
namespace WIDESEAWCS_WCSServer.Filter
{
@@ -23,7 +22,6 @@
            CreateMap<Sys_Menu, MenuDTO>();
            CreateMap<Dt_DeviceInfo,DeviceInfoDTO>();
            CreateMap<WMSTaskDTO, Dt_Task>();
            CreateMap<Dt_Task, ConveyorLineTaskCommand>().ForMember(a => a.TargetAddress, b => b.MapFrom(b => b.NextAddress)).ForMember(a => a.Barcode, b => b.MapFrom(b => b.PalletCode)).ForMember(a => a.TaskNum, b => b.MapFrom(b => b.TaskNum));
        }
    }
}
´úÂë¹ÜÀí/WCS/WCSServers/WIDESEAWCS_Server/appsettings.json
@@ -17,8 +17,7 @@
  //5.PostgreSQL
  "DBType": "SqlServer",
  //连接字符串
  "ConnectionString": "Data Source=.;Initial Catalog=WIDESEAWCS_ShanMei;User ID=sa;Password=123456;Integrated Security=False;Connect Timeout=30;Encrypt=False;TrustServerCertificate=False;ApplicationIntent=ReadWrite;MultiSubnetFailover=False",
  "ConnectionString": "Data Source=.;Initial Catalog=WCS_FengLv;User ID=sa;Password=123456;Integrated Security=False;Connect Timeout=30;Encrypt=False;TrustServerCertificate=False;ApplicationIntent=ReadWrite;MultiSubnetFailover=False",
  //跨域
  "Cors": {
    "PolicyName": "CorsIpAccess", //策略名称
@@ -38,17 +37,17 @@
  "ApiName": "WIDESEAWCS",
  "ExpMinutes": 120,
  "QuartzJobAutoStart": true,
  "DBSeedEnable": false,
  "DBSeedEnable": true,
  "QuartzDBSeedEnable": true,
  "LogDeubgEnable": false, //是否记录调试日志
  "PrintSql": true, //打印SQL语句
  "PrintSql": false, //打印SQL语句
  "LogAOPEnable": true, //是否记录AOP日志
  "WebSocketEnable": true, //是否开启WebSocket服务
  "WebSocketPort": 9296, //WebSocket服务端口
  "WebSocketEnable": false, //是否开启WebSocket服务
  "WebSocketPort": 9260, //WebSocket服务端口
  "SocketServer": {
    "Enabled": true,
    "Port": 2000,
    "IpAddress": "0.0.0.0",
    "Port": 9298,
    "IpAddress": "192.168.0.237",
    "Backlog": 100,
    "EncodingName": "utf-8",
    "AutoDetectEncoding": true,
´úÂë¹ÜÀí/WCS/WCSServers/WIDESEAWCS_TaskInfoService/TaskExecuteDetailService.cs
@@ -57,22 +57,6 @@
                // èŽ·å–ä»»åŠ¡çŠ¶æ€
                int taskState = task.TaskState;
                // å°è¯•将任务状态转换为TaskOutStatusEnum枚举类型
                if (!int.TryParse(Enum.Parse<TaskOutStatusEnum>(taskState.ToString()).ToString(), out int result))
                {
                    // å¦‚果转换失败,则将任务状态转换为TaskInStatusEnum枚举类型
                    if (!int.TryParse(Enum.Parse<TaskInStatusEnum>(taskState.ToString()).ToString(), out result))
                    {
                        // å¦‚果转换失败,则将isNormal设置为false
                        isNormal = false;
                    }
                }
                // å¦‚果转换成功,则判断任务状态是否大于OutFinish
                else if ((int)(TaskOutStatusEnum)result > (int)TaskOutStatusEnum.OutFinish)
                {
                    // å¦‚果大于,则将isNormal设置为false
                    isNormal = false;
                }
                // åˆ›å»ºä»»åŠ¡æ‰§è¡Œè¯¦æƒ…å¯¹è±¡
                Dt_TaskExecuteDetail taskExecuteDetail = new()
                {
@@ -116,16 +100,6 @@
                    int taskNum = task.TaskNum;
                    int taskState = task.TaskState;
                    if (!int.TryParse(Enum.Parse<TaskOutStatusEnum>(taskState.ToString()).ToString(), out int result))
                    {
                        if ((int)(TaskOutStatusEnum)result > (int)TaskOutStatusEnum.OutFinish)
                            isNormal = false;
                    }
                    else if (!int.TryParse(Enum.Parse<TaskInStatusEnum>(taskState.ToString()).ToString(), out result))
                    {
                        if ((int)(TaskInStatusEnum)result > (int)TaskInStatusEnum.InFinish)
                            isNormal = false;
                    }
                    Dt_TaskExecuteDetail taskExecuteDetail = new()
                    {
                        IsManual = App.User.UserId > 0,
@@ -161,57 +135,57 @@
                if (task != null)
                {
                    if (!int.TryParse(Enum.Parse<TaskOutboundTypeEnum>(task.TaskType.ToString()).ToString(), out int result))
                    {
                        steps = Enum.GetValues(typeof(TaskOutStatusEnum)).Cast<int>().Where(x => x <= (int)TaskOutStatusEnum.OutFinish).ToList();
                    //if (!int.TryParse(Enum.Parse<TaskOutboundTypeEnum>(task.TaskType.ToString()).ToString(), out int result))
                    //{
                    //    steps = Enum.GetValues(typeof(TaskOutStatusEnum)).Cast<int>().Where(x => x <= (int)TaskOutStatusEnum.OutFinish).ToList();
                        foreach (var item in steps)
                        {
                            object obj;
                            FieldInfo? fieldInfo = typeof(TaskOutStatusEnum).GetField(((TaskOutStatusEnum)item).ToString());
                            DescriptionAttribute? descriptionAttribute = fieldInfo.GetCustomAttribute<DescriptionAttribute>();
                            if (descriptionAttribute != null)
                            {
                                obj = new { title = item, description = descriptionAttribute.Description };
                            }
                            else
                            {
                                obj = new { title = item, description = ((TaskOutStatusEnum)item).ToString() };
                            }
                            list.Add(obj);
                        }
                    }
                    else if (!int.TryParse(Enum.Parse<TaskInboundTypeEnum>(task.TaskType.ToString()).ToString(), out result))
                    {
                        steps = Enum.GetValues(typeof(TaskInStatusEnum)).Cast<int>().Where(x => x <= (int)TaskInStatusEnum.InFinish).ToList();
                        foreach (var item in steps)
                        {
                            object obj;
                            FieldInfo? fieldInfo = typeof(TaskInStatusEnum).GetField(((TaskInStatusEnum)item).ToString());
                            DescriptionAttribute? descriptionAttribute = fieldInfo.GetCustomAttribute<DescriptionAttribute>();
                            if (descriptionAttribute != null)
                            {
                                obj = new { title = item, description = descriptionAttribute.Description };
                            }
                            else
                            {
                                obj = new { title = item, description = ((TaskInStatusEnum)item).ToString() };
                            }
                            list.Add(obj);
                        }
                    }
                    else if (!int.TryParse(Enum.Parse<TaskRelocationTypeEnum>(task.TaskType.ToString()).ToString(), out result))
                    {
                        //todo è°ƒç”¨WMS移库完成
                    }
                    else if (!int.TryParse(Enum.Parse<TaskOtherTypeEnum>(task.TaskType.ToString()).ToString(), out result))
                    {
                    //    foreach (var item in steps)
                    //    {
                    //        object obj;
                    //        FieldInfo? fieldInfo = typeof(TaskOutStatusEnum).GetField(((TaskOutStatusEnum)item).ToString());
                    //        DescriptionAttribute? descriptionAttribute = fieldInfo.GetCustomAttribute<DescriptionAttribute>();
                    //        if (descriptionAttribute != null)
                    //        {
                    //            obj = new { title = item, description = descriptionAttribute.Description };
                    //        }
                    //        else
                    //        {
                    //            obj = new { title = item, description = ((TaskOutStatusEnum)item).ToString() };
                    //        }
                    //        list.Add(obj);
                    //    }
                    //}
                    //else if (!int.TryParse(Enum.Parse<TaskInboundTypeEnum>(task.TaskType.ToString()).ToString(), out result))
                    //{
                    //    steps = Enum.GetValues(typeof(TaskInStatusEnum)).Cast<int>().Where(x => x <= (int)TaskInStatusEnum.InFinish).ToList();
                    //    foreach (var item in steps)
                    //    {
                    //        object obj;
                    //        FieldInfo? fieldInfo = typeof(TaskInStatusEnum).GetField(((TaskInStatusEnum)item).ToString());
                    //        DescriptionAttribute? descriptionAttribute = fieldInfo.GetCustomAttribute<DescriptionAttribute>();
                    //        if (descriptionAttribute != null)
                    //        {
                    //            obj = new { title = item, description = descriptionAttribute.Description };
                    //        }
                    //        else
                    //        {
                    //            obj = new { title = item, description = ((TaskInStatusEnum)item).ToString() };
                    //        }
                    //        list.Add(obj);
                    //    }
                    //}
                    //else if (!int.TryParse(Enum.Parse<TaskRelocationTypeEnum>(task.TaskType.ToString()).ToString(), out result))
                    //{
                    //    //todo è°ƒç”¨WMS移库完成
                    //}
                    //else if (!int.TryParse(Enum.Parse<TaskOtherTypeEnum>(task.TaskType.ToString()).ToString(), out result))
                    //{
                    }
                    else
                    {
                        throw new Exception($"任务类型错误,未找到该任务类型,任务号:【{taskNum}】,任务类型:【{task.TaskType}】");
                    }
                    //}
                    //else
                    //{
                    //    throw new Exception($"任务类型错误,未找到该任务类型,任务号:【{taskNum}】,任务类型:【{task.TaskType}】");
                    //}
                    active = steps.IndexOf(task.TaskState) + 1;
                }
´úÂë¹ÜÀí/WCS/WCSServers/WIDESEAWCS_TaskInfoService/TaskService.cs
@@ -53,8 +53,6 @@
        public List<int> TaskOutboundTypes => typeof(TaskOutboundTypeEnum).GetEnumIndexList();
        public List<int> TaskRobotTypes => typeof(TaskOtherTypeEnum).GetEnumIndexList();
        public TaskService(ITaskRepository BaseDal, IRouterService routerService, ITaskExecuteDetailService taskExecuteDetailService, ITaskExecuteDetailRepository taskExecuteDetailRepository, IMapper mapper) : base(BaseDal)
        {
            _routerService = routerService;
@@ -82,24 +80,22 @@
                    }
                    Dt_Task task = _mapper.Map<Dt_Task>(item);
                    task.Creater = "WMS";
                    if (task.TaskType.GetTaskTypeGroup() == TaskTypeGroup.OutbondGroup)
                    if (task.TaskType.GetTaskTypeGroup() == TaskTypeGroup.OutbondGroup)//出库
                    {
                        List<Dt_Router> routers = _routerService.QueryNextRoutes(item.RoadWay, item.TargetAddress);
                        //暂不考虑多路径
                        if (routers.Count > 0)
                        {
                            task.TaskState = (int)TaskOutStatusEnum.OutNew;
                            task.TaskState = (int)TaskStatusEnum.New;
                            task.CurrentAddress = item.SourceAddress;
                            task.NextAddress = routers.FirstOrDefault().ChildPosi;
                        }
                    }
                    else if (task.TaskType.GetTaskTypeGroup() == TaskTypeGroup.InboundGroup)
                    else if (task.TaskType.GetTaskTypeGroup() == TaskTypeGroup.InboundGroup)//入库
                    {
                        List<Dt_Router> routers = _routerService.QueryNextRoutes(item.SourceAddress, item.TargetAddress);
                        //暂不考虑多路径
                        if (routers.Count > 0)
                        {
                            task.TaskState = (int)TaskInStatusEnum.InNew;
                            task.TaskState = (int)TaskStatusEnum.New;
                            task.CurrentAddress = item.SourceAddress;
                            task.NextAddress = routers.FirstOrDefault().ChildPosi;
                        }
@@ -130,18 +126,8 @@
            WebResponseContent content = new WebResponseContent();
            try
            {
                WMSTaskDTO taskDTO = new WMSTaskDTO()
                {
                    TaskNum = Convert.ToInt32(DateTime.Now.ToString("HHmmss")),
                    Grade = 1,
                    PalletCode = palletCode,
                    RoadWay = "SC01",
                    SourceAddress = sourceAddress,
                    TargetAddress = "SC01",
                    TaskState = (int)TaskInStatusEnum.InNew,
                    Id = 0,
                    TaskType = (int)TaskInboundTypeEnum.Inbound
                };
                //向WMS请求任务
                WMSTaskDTO taskDTO = new WMSTaskDTO();
                content = ReceiveWMSTask(new List<WMSTaskDTO> { taskDTO });
            }
@@ -160,7 +146,7 @@
        /// <returns></returns>
        public Dt_Task QueryConveyorLineTask(string deviceNo, string currentAddress)
        {
            return BaseDal.QueryFirst(x => (TaskInboundTypes.Contains(x.TaskType) && x.TaskState == (int)TaskInStatusEnum.InNew || TaskOutboundTypes.Contains(x.TaskType) && x.TaskState == (int)TaskOutStatusEnum.SC_OutFinish) && x.CurrentAddress == currentAddress, TaskOrderBy);
            return BaseDal.QueryFirst(x => (TaskInboundTypes.Contains(x.TaskType) || TaskOutboundTypes.Contains(x.TaskType)) && x.TaskState == (int)TaskStatusEnum.Line_Execute && x.CurrentAddress == currentAddress, TaskOrderBy);
        }
        /// <summary>
@@ -171,88 +157,7 @@
        /// <returns></returns>
        public Dt_Task QueryExecutingConveyorLineTask(int taskNum, string nextAddress)
        {
            return BaseDal.QueryFirst(x => x.TaskNum == taskNum && x.NextAddress == nextAddress && (x.TaskState == (int)TaskInStatusEnum.Line_InExecuting || x.TaskState == (int)TaskOutStatusEnum.Line_OutExecuting), TaskOrderBy);
        }
        /// <summary>
        /// æ ¹æ®ä»»åŠ¡å·ã€å½“å‰åœ°å€æŸ¥è¯¢è¾“é€çº¿å®Œæˆçš„ä»»åŠ¡
        /// </summary>
        /// <param name="taskNum">任务号</param>
        /// <param name="currentAddress">当前地址</param>
        /// <returns></returns>
        public Dt_Task QueryCompletedConveyorLineTask(int taskNum, string currentAddress)
        {
            return BaseDal.QueryFirst(x => x.TaskNum == taskNum && x.CurrentAddress == currentAddress && (x.TaskState == (int)TaskInStatusEnum.Line_InFinish || x.TaskState == (int)TaskOutStatusEnum.Line_OutFinish), TaskOrderBy);
        }
        /// <summary>
        /// æ ¹æ®è®¾å¤‡ç¼–号、任务类型分组(可选)按照优先级以及创建时间排序查询任务池新增的任务
        /// </summary>
        /// <param name="deviceNo">设备编号</param>
        /// <param name="taskTypeGroup">任务类型分组(可选)</param>
        /// <returns></returns>
        public Dt_Task? QuertStackerCraneTask(string deviceNo, TaskTypeGroup? taskTypeGroup = null)
        {
            if (taskTypeGroup == null)
                return BaseDal.QueryFirst(x => x.Roadway == deviceNo && (TaskInboundTypes.Contains(x.TaskType) && x.TaskState == (int)TaskInStatusEnum.Line_InFinish || TaskOutboundTypes.Contains(x.TaskType) && x.TaskState == (int)TaskOutStatusEnum.OutNew), TaskOrderBy);
            if (taskTypeGroup.Value == TaskTypeGroup.InboundGroup)
                return BaseDal.QueryFirst(x => x.Roadway == deviceNo && TaskInboundTypes.Contains(x.TaskType) && x.TaskState == (int)TaskInStatusEnum.Line_InFinish, TaskOrderBy);
            if (taskTypeGroup.Value == TaskTypeGroup.OutbondGroup)
                return BaseDal.QueryFirst(x => x.Roadway == deviceNo && TaskOutboundTypes.Contains(x.TaskType) && x.TaskState == (int)TaskOutStatusEnum.OutNew, TaskOrderBy);
            return null;
        }
        /// <summary>
        /// æ ¹æ®è®¾å¤‡ç¼–号、当前地址按照优先级以及创建时间排序查询任务池新增的任务
        /// </summary>
        /// <param name="deviceNo">设备编号</param>
        /// <param name="currentAddress">当前地址</param>
        /// <returns>返回任务实体对象,可能为null</returns>
        public Dt_Task QueryStackerCraneTask(string deviceNo, string currentAddress = "")
        {
            if (string.IsNullOrEmpty(currentAddress))
                return BaseDal.QueryFirst(x => x.Roadway == deviceNo && (TaskInboundTypes.Contains(x.TaskType) && x.TaskState == (int)TaskInStatusEnum.Line_InFinish || TaskOutboundTypes.Contains(x.TaskType) && x.TaskState == (int)TaskOutStatusEnum.OutNew), TaskOrderBy);
            else
                return BaseDal.QueryFirst(x => x.Roadway == deviceNo && x.CurrentAddress == currentAddress && (TaskInboundTypes.Contains(x.TaskType) && x.TaskState == (int)TaskInStatusEnum.Line_InFinish || TaskOutboundTypes.Contains(x.TaskType) && x.TaskState == (int)TaskOutStatusEnum.OutNew), TaskOrderBy);
        }
        /// <summary>
        /// æ ¹æ®è®¾å¤‡ç¼–号、当前地址按照优先级以及创建时间排序查询任务池入库类型的新增的任务
        /// </summary>
        /// <param name="deviceNo">设备编号</param>
        /// <param name="currentAddress">当前地址</param>
        /// <returns>返回任务实体对象,可能为null</returns>
        public Dt_Task QueryStackerCraneInTask(string deviceNo, string currentAddress = "")
        {
            if (string.IsNullOrEmpty(currentAddress))
                return BaseDal.QueryFirst(x => x.Roadway == deviceNo && TaskInboundTypes.Contains(x.TaskType) && x.TaskState == (int)TaskInStatusEnum.Line_InFinish, TaskOrderBy);
            else
                return BaseDal.QueryFirst(x => x.Roadway == deviceNo && TaskInboundTypes.Contains(x.TaskType) && x.TaskState == (int)TaskInStatusEnum.Line_InFinish && x.CurrentAddress == currentAddress, TaskOrderBy);
        }
        /// <summary>
        /// æ ¹æ®è®¾å¤‡ç¼–号、当前地址按照优先级以及创建时间排序查询任务池出库类型的新增的任务
        /// </summary>
        /// <param name="deviceNo">设备编号</param>
        /// <param name="currentAddress">当前地址</param>
        /// <returns>返回任务实体对象,可能为null</returns>
        public Dt_Task QueryStackerCraneOutTask(string deviceNo, string currentAddress = "")
        {
            if (string.IsNullOrEmpty(currentAddress))
                return BaseDal.QueryFirst(x => x.Roadway == deviceNo && TaskOutboundTypes.Contains(x.TaskType) && x.TaskState == (int)TaskOutStatusEnum.OutNew, TaskOrderBy);
            else
                return BaseDal.QueryFirst(x => x.Roadway == deviceNo && TaskOutboundTypes.Contains(x.TaskType) && x.TaskState == (int)TaskOutStatusEnum.OutNew && x.CurrentAddress == currentAddress, TaskOrderBy);
        }
        /// <summary>
        /// æ ¹æ®è®¾å¤‡ç¼–号、当前地址按照优先级以及创建时间排序查询任务池出库类型的新增的任务
        /// </summary>
        /// <param name="deviceNo">设备编号</param>
        /// <param name="currentAddress">当前地址</param>
        /// <returns>返回任务实体对象集合,可能为null</returns>
        public List<Dt_Task> QueryStackerCraneOutTasks(string deviceNo, List<string> outStationCodes)
        {
            return BaseDal.QueryData(x => x.Roadway == deviceNo && TaskOutboundTypes.Contains(x.TaskType) && x.TaskState == (int)TaskOutStatusEnum.OutNew && outStationCodes.Contains(x.CurrentAddress), TaskOrderBy);
            return BaseDal.QueryFirst(x => x.TaskNum == taskNum && x.NextAddress == nextAddress && x.TaskState == (int)TaskStatusEnum.Line_Executing, TaskOrderBy);
        }
        /// <summary>
@@ -267,14 +172,7 @@
            {
                Dt_Task task = BaseDal.QueryFirst(x => x.TaskNum == taskNum);
                if (task == null) return WebResponseContent.Instance.Error($"未找到该任务信息,任务号:【{taskNum}】");
                if (task.TaskType.GetTaskTypeGroup() == TaskTypeGroup.OutbondGroup)
                {
                    task.TaskState = (int)TaskOutStatusEnum.OutPending;
                }
                else if (task.TaskType.GetTaskTypeGroup() == TaskTypeGroup.InboundGroup)
                {
                    task.TaskState = (int)TaskInStatusEnum.InPending;
                }
                task.TaskState = (int)TaskStatusEnum.Pending;
                task.ExceptionMessage = message;
                task.ModifyDate = DateTime.Now;
                BaseDal.UpdateData(task);
@@ -335,44 +233,9 @@
            try
            {
                int oldState = task.TaskState;
                if (task.TaskType.GetTaskTypeGroup() == TaskTypeGroup.OutbondGroup)
                if (task.TaskType.GetTaskTypeGroup() == TaskTypeGroup.OutbondGroup || task.TaskType.GetTaskTypeGroup() == TaskTypeGroup.InboundGroup)
                {
                    if (task.TaskState >= (int)TaskOutStatusEnum.OutFinish)
                    {
                        return content = WebResponseContent.Instance.Error($"该任务状态不可跳转到下一步,任务号:【{task.TaskNum}】,任务状态:【{task.TaskState}】");
                    }
                    int nextStatus = task.TaskState.GetNextNotCompletedStatus<TaskOutStatusEnum>();
                    task.TaskState = nextStatus;
                }
                else if (task.TaskType.GetTaskTypeGroup() == TaskTypeGroup.InboundGroup)
                {
                    if (task.TaskState >= (int)TaskInStatusEnum.InFinish)
                    {
                        return content = WebResponseContent.Instance.Error($"该任务状态不可跳转到下一步,任务号:【{task.TaskNum}】,任务状态:【{task.TaskState}】");
                    }
                    int nextStatus = task.TaskState.GetNextNotCompletedStatus<TaskInStatusEnum>();
                    task.TaskState = nextStatus;
                    if (task.TaskState == (int)TaskInStatusEnum.Line_InFinish)
                    {
                        Random random = new Random();
                        task.CurrentAddress = task.NextAddress;
                        task.NextAddress = $"{random.Next(1, 100).ToString().PadLeft(3, '0')}-{random.Next(1, 100).ToString().PadLeft(3, '0')}-{random.Next(1, 100).ToString().PadLeft(3, '0')}";
                        task.TargetAddress = task.NextAddress;
                    }
                }
                else if (task.TaskType.GetTaskTypeGroup() == TaskTypeGroup.OtherGroup)
                {
                    if (task.TaskState >= (int)TaskRobotStatusEnum.RobotNew)
                    {
                        return content = WebResponseContent.Instance.Error($"该任务状态不可跳转到下一步,任务号:【{task.TaskNum}】,任务状态:【{task.TaskState}】");
                    }
                    int nextStatus = task.TaskState.GetNextNotCompletedStatus<TaskRobotStatusEnum>();
                    int nextStatus = task.TaskState.GetNextNotCompletedStatus<TaskStatusEnum>();
                    task.TaskState = nextStatus;
                }
                else
@@ -448,55 +311,34 @@
                Dt_Task task = BaseDal.QueryFirst(x => x.TaskNum == taskNum);
                if (task == null) return WebResponseContent.Instance.Error($"未找到该任务信息,任务号:【{taskNum}】");
                if (task.TaskType.GetTaskTypeGroup() == TaskTypeGroup.OutbondGroup && task.TaskState == (int)TaskOutStatusEnum.SC_OutExecuting)
                if (task.TaskType.GetTaskTypeGroup() == TaskTypeGroup.OutbondGroup && task.TaskState == (int)TaskStatusEnum.SC_Executing)
                {
                    List<Dt_Router> routers = _routerService.QueryNextRoutes(task.NextAddress, task.TargetAddress);
                    if (!routers.Any()) return WebResponseContent.Instance.Error($"未找到设备路由信息");
                    int nextStatus = task.TaskState.GetNextNotCompletedStatus<TaskOutStatusEnum>();
                    task.TaskState = nextStatus;
                    task.TaskState = (int)TaskStatusEnum.SC_Finish;
                    task.CurrentAddress = task.NextAddress;
                    task.NextAddress = routers.FirstOrDefault().ChildPosi;
                    task.ModifyDate = DateTime.Now;
                    task.Modifier = "System";
                    BaseDal.UpdateData(task);
                    _taskExecuteDetailService.AddTaskExecuteDetail(task.TaskId, $"堆垛机出库完成");
                    //todo åŒæ­¥åˆ°WMS
                    //暂不考虑多个出库口
                }
                else if (task.TaskType.GetTaskTypeGroup() == TaskTypeGroup.InboundGroup && task.TaskState == (int)TaskInStatusEnum.SC_InExecuting)
                else if (task.TaskType.GetTaskTypeGroup() == TaskTypeGroup.InboundGroup && task.TaskState == (int)TaskStatusEnum.SC_Executing)
                {
                    //todo
                    int nextStatus = task.TaskState.GetNextNotCompletedStatus<TaskInStatusEnum>();
                    task.TaskState = nextStatus;
                    task.TaskState = (int)TaskStatusEnum.Finish;
                    task.ModifyDate = DateTime.Now;
                    task.Modifier = "System";
                    BaseDal.UpdateData(task);
                    _taskExecuteDetailService.AddTaskExecuteDetail(task.TaskId, $"堆垛机入库完成");
                    WMSTaskDTO taskDTO = new WMSTaskDTO()
                    {
                        TaskNum = Convert.ToInt32(DateTime.Now.ToString("HHmmss")),
                        Grade = 1,
                        PalletCode = task.PalletCode + "S",
                        RoadWay = "SC01",
                        SourceAddress = task.TargetAddress,
                        TargetAddress = "CLOutAreaA",
                        TaskState = (int)TaskOutStatusEnum.OutNew,
                        Id = 0,
                        TaskType = (int)TaskOutboundTypeEnum.Outbound
                    };
                    content = ReceiveWMSTask(new List<WMSTaskDTO> { taskDTO });
                    //todo åŒæ­¥åˆ°WMS
                }
                else if (task.TaskType.GetTaskTypeGroup() == TaskTypeGroup.RelocationGroup)
                {
                    //todo è°ƒç”¨WMS移库完成
                }
                else if (task.TaskType.GetTaskTypeGroup() == TaskTypeGroup.OtherGroup)
                {
                }
                else
                {
@@ -523,7 +365,7 @@
            {
                Dt_Task task = BaseDal.QueryFirst(x => x.TaskNum == taskNum);
                if (task == null) return WebResponseContent.Instance.Error($"未找到该任务信息,任务号:【{taskNum}】");
                if (task.TaskState != (int)TaskInStatusEnum.InPending && task.TaskState != (int)TaskOutStatusEnum.OutPending)
                if (task.TaskState != (int)TaskStatusEnum.Pending)
                {
                    return content = WebResponseContent.Instance.Error($"该任务状态不可恢复,任务号:【{taskNum}】,任务状态:【{task.TaskState}】");
                }
@@ -537,11 +379,11 @@
                {
                    if (task.TaskType.GetTaskTypeGroup() == TaskTypeGroup.OutbondGroup)
                    {
                        task.TaskState = (int)TaskOutStatusEnum.OutNew;
                        task.TaskState = (int)TaskStatusEnum.New;
                    }
                    else if (task.TaskType.GetTaskTypeGroup() == TaskTypeGroup.InboundGroup)
                    {
                        task.TaskState = (int)TaskInStatusEnum.InNew;
                        task.TaskState = (int)TaskStatusEnum.New;
                    }
                    //todo
                }
@@ -612,20 +454,6 @@
            List<Dt_Task> tasks = BaseDal.QueryData(x => taskKeys.Contains(x.TaskId));
            BaseDal.DeleteAndMoveIntoHty(tasks, OperateTypeEnum.人工删除);
            return WebResponseContent.Instance.OK($"成功删除{tasks.Count}条数据");
        }
        /// <summary>
        /// æ ¹æ®è®¾å¤‡ç¼–号、当前地址按照优先级以及创建时间排序查询任务池新增的任务
        /// </summary>
        /// <param name="deviceNo">设备编号</param>
        /// <param name="currentAddress">当前地址</param>
        /// <returns>返回任务实体对象,可能为null</returns>
        public Dt_Task QueryRobotCraneTask(string deviceNo, string currentAddress = "")
        {
            if (string.IsNullOrEmpty(currentAddress))
                return BaseDal.QueryFirst(x => x.Roadway == deviceNo && (TaskRobotTypes.Contains(x.TaskType) && x.TaskState <= (int)TaskRobotStatusEnum.RobotExecuting), TaskOrderBy);
            else
                return BaseDal.QueryFirst(x => x.Roadway == deviceNo && TaskRobotTypes.Contains(x.TaskType) && x.CurrentAddress == currentAddress && x.TaskState <= (int)TaskRobotStatusEnum.RobotExecuting, TaskOrderBy);
        }
    }
}
´úÂë¹ÜÀí/WCS/WCSServers/WIDESEAWCS_Tasks/ConveyorLineJob/CommonConveyorLineJob.cs
ÎļþÒÑɾ³ý
´úÂë¹ÜÀí/WCS/WCSServers/WIDESEAWCS_Tasks/ConveyorLineJob/ConveyorLineDBName.cs
ÎļþÒÑɾ³ý
´úÂë¹ÜÀí/WCS/WCSServers/WIDESEAWCS_Tasks/ConveyorLineJob/ConveyorLineTaskCommand.cs
ÎļþÒÑɾ³ý
´úÂë¹ÜÀí/WCS/WCSServers/WIDESEAWCS_Tasks/FormationStackerCraneJob/FormationCommonStackerCraneJob.cs
ÎļþÒÑɾ³ý
´úÂë¹ÜÀí/WCS/WCSServers/WIDESEAWCS_Tasks/FormationStackerCraneJob/FormationStackerCraneDBName.cs
ÎļþÒÑɾ³ý
´úÂë¹ÜÀí/WCS/WCSServers/WIDESEAWCS_Tasks/FormationStackerCraneJob/FormationStackerCraneTaskCommand.cs
ÎļþÒÑɾ³ý
´úÂë¹ÜÀí/WCS/WCSServers/WIDESEAWCS_Tasks/RobotJob/RobotJob.cs
ÎļþÒÑɾ³ý
´úÂë¹ÜÀí/WCS/WCSServers/WIDESEAWCS_Tasks/SerialPortJob.cs
ÎļþÒÑɾ³ý
´úÂë¹ÜÀí/WCS/WCSServers/WIDESEAWCS_Tasks/ShuttleCarJob/ShuttleCarJob.cs
ÎļþÒÑɾ³ý
´úÂë¹ÜÀí/WCS/WCSServers/WIDESEAWCS_Tasks/SocketServer/SocketServerOptions.cs
@@ -25,7 +25,7 @@
        /// <summary>
        /// è¿žæŽ¥é˜Ÿåˆ—长度
        /// </summary>
        public int Backlog { get; set; } = 100;
        public int Backlog { get; set; } = 1000;
        /// <summary>
        /// æ–‡æœ¬ç¼–码名称(例如: utf-8, gbk)
@@ -51,5 +51,15 @@
        /// æ—¥å¿—文件路径(相对于程序运行目录)
        /// </summary>
        public string LogFilePath { get; set; } = "socketserver.log";
        /// <summary>
        /// æ¶ˆæ¯å¤´æ ‡è®°
        /// </summary>
        public string MessageHeader { get; set; } = "<";
        /// <summary>
        /// æ¶ˆæ¯å°¾æ ‡è®°
        /// </summary>
        public string MessageFooter { get; set; } = ">";
    }
}
´úÂë¹ÜÀí/WCS/WCSServers/WIDESEAWCS_Tasks/SocketServer/TcpSocketServer.Clients.cs
@@ -9,6 +9,11 @@
{
    public partial class TcpSocketServer
    {
        /// <summary>
        /// æ£€ç´¢å½“前在服务中注册的所有客户端标识符的只读列表。
        /// </summary>
        /// <remarks>返回的列表表示调用时刻客户端ID的快照。后续对客户端集合的更改不会影响返回的列表。此方法是线程安全的。</remarks>
        /// <returns>包含客户端ID的<see cref="IReadOnlyList{String}"/>。如果没有客户端注册,列表将为空。</returns>
        public IReadOnlyList<string> GetClientIds()
        {
            lock (_syncRoot)
@@ -17,6 +22,12 @@
            }
        }
        /// <summary>
        /// æ£€ç´¢ä¸ŽæŒ‡å®šè®¾å¤‡æ ‡è¯†ç¬¦å…³è”的客户端标识符。
        /// </summary>
        /// <remarks>此方法是线程安全的。如果未找到设备标识符,方法将返回null而不是抛出异常。</remarks>
        /// <param name="deviceId">要检索客户端标识符的设备的唯一标识符。不能为null。</param>
        /// <returns>与指定设备标识符关联的客户端标识符,如果不存在关联则返回null。</returns>
        public string? GetClientIdByDevice(string deviceId)
        {
            lock (_syncRoot)
@@ -25,6 +36,14 @@
            }
        }
        /// <summary>
        /// å¼‚步向指定设备发送消息。
        /// </summary>
        /// <remarks>如果指定设备未注册或无法找到,则返回 <see langword="false"/>。</remarks>
        /// <param name="deviceId">目标设备的唯一标识符。不能为null或空。</param>
        /// <param name="message">要发送给设备的消息。不能为null。</param>
        /// <returns>表示异步操作的任务。如果消息成功发送,任务结果为 <see langword="true"/>;
        /// å¦åˆ™ä¸º <see langword="false"/>。</returns>
        public Task<bool> SendToDeviceAsync(string deviceId, string message)
        {
            var clientId = GetClientIdByDevice(deviceId);
@@ -32,6 +51,16 @@
            return SendToClientAsync(clientId, message);
        }
        /// <summary>
        /// é€šè¿‡TCP连接异步向指定客户端发送带帧的文本消息。
        /// </summary>
        /// <remarks>如果客户端未连接或不存在,此方法将返回 <see langword="false"/> ä¸”不发送消息。
        /// æ¶ˆæ¯å°†ä¼˜å…ˆä½¿ç”¨å®¢æˆ·ç«¯é¦–选的文本编码进行编码;否则使用默认编码。
        /// æ­¤æ–¹æ³•对于向不同客户端的并发调用是线程安全的。</remarks>
        /// <param name="clientId">要发送消息到的客户端的唯一标识符。必须对应已连接的客户端。</param>
        /// <param name="message">要发送给客户端的文本消息。不能为null。</param>
        /// <returns>表示异步操作的任务。如果消息成功发送,任务结果为 <see langword="true"/>;
        /// å¦åˆ™ï¼Œå¦‚果客户端未连接或不存在,结果为 <see langword="false"/>。</returns>
        public async Task<bool> SendToClientAsync(string clientId, string message)
        {
            TcpClient? client;
@@ -55,7 +84,8 @@
            try
            {
                var ns = client.GetStream();
                var data = enc.GetBytes((message ?? string.Empty) + "\n");
                var framedMessage = BuildFramedMessage(message);
                var data = enc.GetBytes(framedMessage);
                await ns.WriteAsync(data, 0, data.Length);
            }
            finally
@@ -65,6 +95,13 @@
            return true;
        }
        /// <summary>
        /// å¼‚步向所有已连接的客户端发送指定的消息。
        /// </summary>
        /// <remarks>如果向某个客户端发送消息时发生错误,异常将被抑制并继续向其他客户端广播。
        /// å½“所有发送操作完成后,此方法结束。</remarks>
        /// <param name="message">要广播给所有客户端的消息。不能为null。</param>
        /// <returns>表示异步广播操作的任务。</returns>
        public async Task BroadcastAsync(string message)
        {
            List<TcpClient> clients;
@@ -75,11 +112,19 @@
            await Task.WhenAll(clients.Select(c => Task.Run(async () =>
            {
                try { await SendAsync(c, message); } catch { }
                try { await SendMessageAsync(c, message); } catch { }
            })));
        }
        public static async Task SendAsync(TcpClient client, string message)
        /// <summary>
        /// é€šè¿‡ç½‘络流异步向指定的TCP客户端发送带帧的文本消息。
        /// </summary>
        /// <remarks>如果客户端为null或未连接,此方法将立即返回而不发送消息。
        /// æ¶ˆæ¯å°†ä½¿ç”¨é…ç½®çš„æ–‡æœ¬ç¼–码进行编码并添加帧头后通过网络流发送。</remarks>
        /// <param name="client">要发送消息到的TCP客户端。必须处于连接状态;否则方法不执行任何操作。</param>
        /// <param name="message">要发送给客户端的文本消息。消息在传输前将被编码并添加帧头。</param>
        /// <returns>表示异步发送操作的任务。</returns>
        private async Task SendMessageAsync(TcpClient client, string message)
        {
            if (client == null || !client.Connected)
            {
@@ -87,7 +132,8 @@
            }
            NetworkStream stream = client.GetStream();
            var data = Encoding.UTF8.GetBytes((message ?? string.Empty) + "\n");
            var framedMessage = BuildFramedMessage(message);
            var data = _textEncoding.GetBytes(framedMessage);
            await stream.WriteAsync(data, 0, data.Length);
        }
    }
´úÂë¹ÜÀí/WCS/WCSServers/WIDESEAWCS_Tasks/SocketServer/TcpSocketServer.Dispose.cs
@@ -5,6 +5,11 @@
{
    public partial class TcpSocketServer
    {
        /// <summary>
        /// é‡Šæ”¾æœåŠ¡å™¨ä½¿ç”¨çš„æ‰€æœ‰èµ„æºå¹¶åœæ­¢ç›‘å¬ä¼ å…¥è¿žæŽ¥ã€‚
        /// </summary>
        /// <remarks>当不再需要服务器时调用此方法,以确保所有相关资源(如网络监听器和同步原语)被正确释放。
        /// è°ƒç”¨ <see cref="Dispose"/> åŽï¼ŒæœåŠ¡å™¨æ— æ³•é‡æ–°å¯åŠ¨æˆ–å†æ¬¡ä½¿ç”¨ã€‚</remarks>
        public void Dispose()
        {
            _cts?.Cancel();
´úÂë¹ÜÀí/WCS/WCSServers/WIDESEAWCS_Tasks/SocketServer/TcpSocketServer.Messaging.cs
@@ -1,17 +1,24 @@
using HslCommunication.Core.IMessage;
using System;
using System.Net.Sockets;
using System.Text;
using System.Text.Json;
using System.Threading;
using System.Threading.Tasks;
using WIDESEAWCS_QuartzJob;
using System.IO;
namespace WIDESEAWCS_Tasks.SocketServer
{
    public partial class TcpSocketServer
    {
        public async Task HandleClientAsync(TcpClient client, string clientId, CancellationToken cancellationToken, RobotSocketState robotCrane)
        /// <summary>
        /// å¼‚步处理与已连接的TCP客户端的通信,处理机器人起重机会话中的传入消息和客户端状态更新。
        /// </summary>
        /// <remarks>此方法管理客户端连接的生命周期,包括读取消息、更新客户端状态和调用相关事件。
        /// å½“处理结束时,客户端和相关的网络资源将被释放。如果启用心跳或空闲超时选项,
        /// å°†åº”用额外的取消逻辑。事件调用期间的异常将被捕获并抑制,以确保会话处理的鲁棒性。</remarks>
        /// <param name="client">表示要处理的远程连接的TCP客户端。方法完成后将释放此对象。</param>
        /// <param name="clientId">已连接客户端的唯一标识符。用于在整个会话中跟踪和更新客户端状态。</param>
        /// <param name="cancellationToken">可用于取消客户端处理操作的取消令牌。如果请求取消,方法将立即终止处理。</param>
        /// <param name="stackerState">表示与客户端关联的机器人起重机的当前状态对象。用于为消息处理和事件调用提供上下文。</param>
        /// <returns>表示处理客户端连接的异步操作的任务。当客户端断开连接或请求取消时任务完成。</returns>
        public async Task HandleClientAsync(TcpClient client, string clientId, CancellationToken cancellationToken, StackerSocketState stackerState)
        {
            using (client)
            using (NetworkStream networkStream = client.GetStream())
@@ -32,7 +39,8 @@
                        try
                        {
                            var ct = localCts?.Token ?? cancellationToken;
                            message = await reader.ReadLineAsync().WaitAsync(ct);
                            message = await ReceiveFullMessageAsync(networkStream, _textEncoding, ct);
                            //message = await reader.ReadLineAsync().WaitAsync(ct);
                        }
                        catch (OperationCanceledException)
                        {
@@ -57,9 +65,9 @@
                        {
                            try
                            {
                                _ = MessageReceived.Invoke(message, false, client, robotCrane);
                                // åˆ¤æ–­æ˜¯å¦ä¸º JSON æ ¼å¼
                                bool isJsonFormat = TryParseJsonSilent(message);
                                _ = MessageReceived.Invoke(message, isJsonFormat, client, stackerState);
                            }
                            catch { }
                        }
@@ -74,6 +82,18 @@
            }
        }
        /// <summary>
        /// å°è¯•处理来自客户端的设备注册请求。返回一个值指示该消息是否被作为注册请求处理。
        /// </summary>
        /// <remarks>如果消息是有效的注册请求且包含非空的设备标识符,
        /// åˆ™å°†è®¾å¤‡ç»‘定到客户端并发送确认信息。此方法不会因无效消息而抛出异常;
        /// å®ƒä»…返回 false。</remarks>
        /// <param name="messageLower">客户端消息的小写版本,用于判断消息是否为注册请求。</param>
        /// <param name="message">包含注册命令和设备标识符的原始客户端消息。</param>
        /// <param name="clientId">发送注册请求的客户端的唯一标识符。</param>
        /// <param name="client">与客户端通信的TCP客户端连接。</param>
        /// <param name="cancellationToken">可用于取消注册操作的取消令牌。</param>
        /// <returns>如果消息被识别并作为注册请求处理,则返回 true;否则返回 false。</returns>
        private bool TryHandleRegister(string messageLower, string message, string clientId, NetworkStream networkStream, CancellationToken cancellationToken)
        {
            if (!messageLower.StartsWith("register,"))
@@ -95,6 +115,11 @@
            return true;
        }
        /// <summary>
        /// æ›´æ–°å®¢æˆ·ç«¯çŠ¶æ€
        /// </summary>
        /// <param name="clientId"></param>
        /// <param name="message"></param>
        private void UpdateClientStatus(string clientId, string message)
        {
            lock (_syncRoot)
@@ -116,6 +141,14 @@
            }
        }
        /// <summary>
        /// å†™å…¥æ¶ˆæ¯åˆ°å®¢æˆ·ç«¯
        /// </summary>
        /// <param name="clientId"></param>
        /// <param name="networkStream"></param>
        /// <param name="message"></param>
        /// <param name="cancellationToken"></param>
        /// <returns></returns>
        private async Task WriteToClientAsync(string clientId, NetworkStream networkStream, string message, CancellationToken cancellationToken)
        {
            SemaphoreSlim? sem = null;
@@ -131,7 +164,8 @@
            if (sem != null) await sem.WaitAsync(cancellationToken);
            try
            {
                var data = enc.GetBytes(message + "\n");
                var framedMessage = BuildFramedMessage(message);
                var data = enc.GetBytes(framedMessage);
                await networkStream.WriteAsync(data, 0, data.Length, cancellationToken);
            }
            finally
@@ -140,6 +174,23 @@
            }
        }
        /// <summary>
        /// æ·»åŠ æ¶ˆæ¯å¸§å¤´å°¾
        /// </summary>
        /// <param name="message"></param>
        /// <returns></returns>
        private string BuildFramedMessage(string message)
        {
            var header = _options.MessageHeader ?? string.Empty;
            var footer = _options.MessageFooter ?? string.Empty;
            return header + (message ?? string.Empty) + footer;
        }
        /// <summary>
        /// JSON格式尝试解析(静默失败)
        /// </summary>
        /// <param name="message"></param>
        /// <returns></returns>
        private static bool TryParseJsonSilent(string message)
        {
            if (string.IsNullOrWhiteSpace(message)) return false;
@@ -148,6 +199,11 @@
            try { JsonDocument.Parse(message); return true; } catch { return false; }
        }
        /// <summary>
        /// utf-8 å¯èƒ½æ€§æ£€æµ‹
        /// </summary>
        /// <param name="data"></param>
        /// <returns></returns>
        private static bool IsLikelyUtf8(byte[] data)
        {
            int i = 0;
@@ -177,5 +233,58 @@
            }
            return true;
        }
        /// <summary>
        /// è¯»å–完整消息
        /// </summary>
        /// <param name="networkStream">字节流</param>
        /// <param name="encoding">编码格式</param>
        /// <param name="cancellationToken"></param>
        /// <returns></returns>
        private async Task<string?> ReceiveFullMessageAsync(NetworkStream networkStream, Encoding encoding, CancellationToken cancellationToken)
        {
            var header = _options.MessageHeader ?? string.Empty;
            var footer = _options.MessageFooter ?? string.Empty;
            var buffer = new byte[1024];
            var builder = new StringBuilder();
            while (true)
            {
                int bytesRead = await networkStream.ReadAsync(buffer.AsMemory(0, buffer.Length), cancellationToken);
                if (bytesRead <= 0)
                {
                    if (builder.Length == 0) return null;
                    return string.IsNullOrEmpty(header) && string.IsNullOrEmpty(footer) ? builder.ToString() : null;
                }
                builder.Append(encoding.GetString(buffer, 0, bytesRead));
                if (string.IsNullOrEmpty(header) && string.IsNullOrEmpty(footer))
                {
                    if (!networkStream.DataAvailable)
                    {
                        break;
                    }
                    continue;
                }
                var data = builder.ToString();
                var headerIndex = string.IsNullOrEmpty(header) ? 0 : data.IndexOf(header, StringComparison.Ordinal);
                if (headerIndex < 0)
                {
                    continue;
                }
                var startIndex = headerIndex + header.Length;
                var footerIndex = string.IsNullOrEmpty(footer) ? data.Length : data.IndexOf(footer, startIndex, StringComparison.Ordinal);
                if (footerIndex >= 0)
                {
                    return data.Substring(startIndex, footerIndex - startIndex);
                }
            }
            return builder.ToString();
        }
    }
}
´úÂë¹ÜÀí/WCS/WCSServers/WIDESEAWCS_Tasks/SocketServer/TcpSocketServer.Server.cs
@@ -10,6 +10,13 @@
{
    public partial class TcpSocketServer
    {
        /// <summary>
        /// å¼‚步启动TCP服务器,使其开始接受传入的客户端连接。
        /// </summary>
        /// <remarks>如果服务器已在运行或通过配置禁用,此方法将立即返回而不启动服务器。
        /// åŽç»­çš„客户端监控和接受操作在后台任务中运行。此方法不会阻塞调用线程。</remarks>
        /// <param name="cancellationToken">可用于请求取消服务器启动及后续后台操作的取消令牌。</param>
        /// <returns>表示异步启动操作的任务。当服务器开始监听连接时任务完成。</returns>
        public Task StartAsync(CancellationToken cancellationToken)
        {
            if (IsRunning || !_options.Enabled)
@@ -34,6 +41,13 @@
            return Task.CompletedTask;
        }
        //// <summary>
        /// å¼‚步停止服务器并等待所有活动客户端连接完成。
        /// </summary>
        /// <remarks>如果服务器未运行,此方法将立即返回而不执行任何操作。
        /// æ­¤æ–¹æ³•确保所有客户端任务完成后才将服务器标记为已停止。</remarks>
        /// <param name="cancellationToken">可用于在完成前取消停止操作的取消令牌。</param>
        /// <returns>表示异步停止操作的任务。</returns>
        public async Task StopAsync(CancellationToken cancellationToken)
        {
            if (!IsRunning)
@@ -58,6 +72,13 @@
            IsRunning = false;
        }
        /// <summary>
        /// æŒç»­æŽ¥å—传入的TCP客户端连接,直到请求取消。
        /// </summary>
        /// <remarks>此方法旨在后台运行以处理新的客户端连接。
        /// å¦‚果监听器被释放或通过提供的令牌请求取消,循环将退出。</remarks>
        /// <param name="cancellationToken">可用于请求取消接受循环的令牌。当请求取消时,循环将立即终止。</param>
        /// <returns>表示异步接受循环操作的任务。</returns>
        private async Task AcceptLoopAsync(CancellationToken cancellationToken)
        {
            while (!cancellationToken.IsCancellationRequested)
@@ -97,6 +118,12 @@
            }
        }
        /// <summary>
        /// ä»Žå†…部集合中移除指定标识符的客户端,并释放相关资源。
        /// </summary>
        /// <remarks>此方法关闭客户端连接,释放任何关联的锁,并移除对客户端的所有引用,
        /// åŒ…括设备绑定和编码信息。通过对内部同步对象加锁确保线程安全。</remarks>
        /// <param name="clientId">要移除的客户端的唯一标识符。不能为null或空。</param>
        private void RemoveClient(string clientId)
        {
            lock (_syncRoot)
@@ -124,6 +151,13 @@
            }
        }
        /// <summary>
        /// å¼‚步监控已连接的客户端,并断开超过配置超时时间闲置的客户端连接。
        /// </summary>
        /// <remarks>此方法持续检查闲置客户端,如果其不活动时间超过指定的空闲超时,则断开连接。
        /// ç›‘控循环将持续运行,直到通过提供的令牌请求取消。</remarks>
        /// <param name="cancellationToken">可用于请求终止监控循环的取消令牌。</param>
        /// <returns>表示异步监控操作的任务。</returns>
        private async Task MonitorClientsAsync(CancellationToken cancellationToken)
        {
            while (!cancellationToken.IsCancellationRequested)
@@ -156,6 +190,13 @@
            }
        }
        /// <summary>
        /// åŸºäºŽè¿œç¨‹ç»ˆç«¯ç‚¹èŽ·å–æŒ‡å®šTCP客户端的唯一标识符字符串。
        /// </summary>
        /// <remarks>返回的标识符适用于在日志记录或跟踪场景中区分客户端。
        /// å¦‚果客户端的远程终端点不可用,将生成GUID以确保唯一性。</remarks>
        /// <param name="client">要获取标识符的TCP客户端。不能为null。</param>
        /// <returns>表示客户端远程终端点的字符串(如果可用);否则为生成的新GUID字符串。</returns>
        public static string GetClientId(TcpClient client)
        {
            return client.Client.RemoteEndPoint?.ToString() ?? Guid.NewGuid().ToString();
´úÂë¹ÜÀí/WCS/WCSServers/WIDESEAWCS_Tasks/SocketServer/TcpSocketServer.cs
@@ -16,20 +16,81 @@
    public partial class TcpSocketServer : IDisposable
    {
        private readonly SocketServerOptions _options;
        /// <summary>
        /// æä¾›ä¸€ä¸ªå¯ç”¨äºŽåŒæ­¥å¯¹åŒ…含实例的访问的对象。
        /// </summary>
        /// <remarks>在对实例实现线程安全操作时,可将此对象用作锁定目标。此模式通常用于避免死锁并确保一致的同步。</remarks>
        public readonly object _syncRoot = new();
        private TcpListener? _listener;
        /// <summary>
        /// è¡¨ç¤ºç”¨äºŽå‘出进行中操作的取消请求的取消令牌源。
        /// </summary>
        /// <remarks>如果当前没有活动的取消机制,此字段可能为null。使用此令牌源取消支持取消的任务或操作。</remarks>
        public CancellationTokenSource? _cts;
        /// <summary>
        /// æä¾›è¡¨ç¤ºæ´»åŠ¨å®¢æˆ·ç«¯æ“ä½œçš„ä»»åŠ¡åˆ—è¡¨ã€‚
        /// </summary>
        /// <remarks>此字段用于内部跟踪异步客户端活动。它是只读的,不应在包含类外部直接修改。</remarks>
        public readonly List<Task> _clientTasks = new();
        /// <summary>
        /// æä¾›ä»Žå®¢æˆ·ç«¯æ ‡è¯†ç¬¦åˆ°å…¶å…³è”çš„TCP客户端连接的映射。
        /// </summary>
        /// <remarks>此字典允许通过唯一字符串标识符访问活动的TCP客户端。在多线程场景中,对集合的修改应小心进行以避免并发问题。</remarks>
        public readonly Dictionary<string, TcpClient> _clients = new();
        /// <summary>
        /// æä¾›ä»Žè®¾å¤‡æ ‡è¯†ç¬¦åˆ°å…¶å¯¹åº”绑定值的映射。
        /// </summary>
        /// <remarks>此字段是只读的,用于包含类内部使用。应通过指定的方法或属性对字典进行修改以确保一致性。</remarks>
        public readonly Dictionary<string, string> _deviceBindings = new();
        /// <summary>
        /// æä¾›ä»Žå®¢æˆ·ç«¯æ ‡è¯†ç¬¦åˆ°å…¶å…³è”锁的映射,用于同步对客户端特定资源的访问。
        /// </summary>
        /// <remarks>字典中的每个条目将一个唯一的客户端ID与一个<see cref="SemaphoreSlim"/>实例关联,实现每个客户端的线程安全操作。此集合用于内部协调并发访问,不应直接修改。</remarks>
        public readonly Dictionary<string, SemaphoreSlim> _clientLocks = new();
        /// <summary>
        /// æä¾›ä»Žå®¢æˆ·ç«¯æ ‡è¯†ç¬¦åˆ°å…¶å…³è”文本编码的映射。
        /// </summary>
        /// <remarks>此字典用于内部跟踪已连接客户端的编码偏好。键表示客户端标识符,值指定用于文本操作的对应<see cref="System.Text.Encoding"/>。</remarks>
        public readonly Dictionary<string, Encoding> _clientEncodings = new();
        /// <summary>
        /// å­˜å‚¨æ¯ä¸ªå®¢æˆ·ç«¯æœ€åŽæ´»åŠ¨çš„æ—¶é—´æˆ³ï¼Œä»¥å®¢æˆ·ç«¯æ ‡è¯†ç¬¦ä¸ºé”®ã€‚
        /// </summary>
        /// <remarks>此字段用于内部跟踪客户端活动。字典将客户端标识符映射到对应的最后活动时间(UTC)。直接修改此集合可能影响客户端会话管理逻辑。</remarks>
        public readonly Dictionary<string, DateTime> _clientLastActive = new();
        /// <summary>
        /// æŒ‡å®šåŒ…含类型中字符数据使用的文本编码。
        /// </summary>
        /// <remarks>使用此字段确定处理字符数据时如何编码或解码文本。编码影响字节如何被解释为字符,反之亦然。常见的编码包括UTF8、ASCII和Unicode。</remarks>
        public readonly Encoding _textEncoding;
        /// <summary>
        /// è¡¨ç¤ºè‡ªåŠ¨æ£€æµ‹åˆ°çš„GB2312编码(如果可用)。
        /// </summary>
        /// <remarks>通常从输入数据确定编码时设置此字段。如果检测失败或未执行检测,值可能为null。</remarks>
        public readonly Encoding? _autoDetectedGb2312;
        private readonly string _logFile;
        private Task? _monitorTask;
        /// <summary>
        /// ä½¿ç”¨æŒ‡å®šçš„æœåŠ¡å™¨é€‰é¡¹åˆå§‹åŒ– TcpSocketServer ç±»çš„æ–°å®žä¾‹ã€‚
        /// </summary>
        /// <remarks>如果启用了 AutoDetectEncoding é€‰é¡¹ï¼ŒæœåŠ¡å™¨å°†é»˜è®¤ä½¿ç”¨ UTF-8 ç¼–码,
        /// å¹¶å°è¯•支持 GBK ç¼–码进行自动检测。如果编码检测失败或提供了无效的编码名称,
        /// å°†å›žé€€ä½¿ç”¨ UTF-8 ç¼–码。日志文件路径由 LogFilePath é€‰é¡¹å†³å®šï¼Œ
        /// å¦‚果未指定,则默认为应用程序基目录下的 'socketserver.log' æ–‡ä»¶ã€‚</remarks>
        /// <param name="options">套接字服务器的配置选项。不能为 null。提供编码设置、日志文件路径和自动检测行为等配置。</param>
        public TcpSocketServer(IOptions<SocketServerOptions> options)
        {
            _options = options.Value;
@@ -51,7 +112,8 @@
        public bool IsRunning { get; private set; }
        public event Func<string, bool, TcpClient, RobotSocketState, Task<string?>>? MessageReceived;
        public event Func<string, bool, TcpClient, StackerSocketState, Task<string?>>? MessageReceived;
        public event Func<string, Task<string?>>? RobotReceived;
        private void Log(string message)
´úÂë¹ÜÀí/WCS/WCSServers/WIDESEAWCS_Tasks/StackerCraneJob/CommonStackerCraneJob.cs
ÎļþÒÑɾ³ý
´úÂë¹ÜÀí/WCS/WCSServers/WIDESEAWCS_Tasks/StackerCraneJob/StackerCraneDBName.cs
ÎļþÒÑɾ³ý
´úÂë¹ÜÀí/WCS/WCSServers/WIDESEAWCS_Tasks/StackerCraneJob/StackerCraneJob.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,206 @@
using Quartz;
using System.Collections.Concurrent;
using System.Net.Sockets;
using WIDESEAWCS_Core.Helper;
using WIDESEAWCS_ITaskInfoRepository;
using WIDESEAWCS_ITaskInfoService;
using WIDESEAWCS_Model.Models;
using WIDESEAWCS_QuartzJob;
using WIDESEAWCS_QuartzJob.Service;
using WIDESEAWCS_Tasks.SocketServer;
namespace WIDESEAWCS_Tasks
{
    [DisallowConcurrentExecution]
    public class StackerCraneJob : IJob
    {
        private readonly TcpSocketServer _TcpSocket;
        private static readonly ConcurrentDictionary<string, StackerSocketState> _socketStates = new();
        private static int _eventSubscribedFlag;
        private readonly ITaskService _taskService;
        private readonly ITaskExecuteDetailService _taskExecuteDetailService;
        private readonly ITaskRepository _taskRepository;
        private readonly IRouterService _routerService;
        public StackerCraneJob(TcpSocketServer TcpSocket, ITaskService taskService, ITaskExecuteDetailService taskExecuteDetailService, ITaskRepository taskRepository, IRouterService routerService)
        {
            _TcpSocket = TcpSocket;
            _taskService = taskService;
            _taskExecuteDetailService = taskExecuteDetailService;
            _taskRepository = taskRepository;
            _routerService = routerService;
        }
        public async Task Execute(IJobExecutionContext context)
        {
            bool flag = context.JobDetail.JobDataMap.TryGetValue("JobParams", out object? value);
            StackerCraneDevice Crane = (StackerCraneDevice?)value ?? new StackerCraneDevice();
            if (!flag || Crane.IsNullOrEmpty())
            {
                return;
            }
            string ipAddress = Crane.IPAddress;
            // èŽ·å–æˆ–åˆ›å»ºçŠ¶æ€
            StackerSocketState state = _socketStates.GetOrAdd(ipAddress, _ => new StackerSocketState
            {
                IPAddress = ipAddress,
                StackerCrane = Crane
            });
            // æ›´æ–°è®¾å¤‡ä¿¡æ¯
            state.StackerCrane = Crane;
            // æ£€æŸ¥æ˜¯å¦æœ‰è¯¥å®¢æˆ·ç«¯è¿žæŽ¥
            var clientIds = _TcpSocket.GetClientIds();
            if (!clientIds.Contains(ipAddress))
            {
                return;
            }
            // è®¢é˜…一次 message äº‹ä»¶ï¼ˆå…¨å±€ä¸€æ¬¡ï¼‰
            if (Interlocked.CompareExchange(ref _eventSubscribedFlag, 1, 0) == 0)
            {
                _TcpSocket.MessageReceived += _TcpSocket_MessageReceived;
                _TcpSocket.RobotReceived += _TcpSocket_RobotReceived;
            }
            if (!state.IsEventSubscribed)
            {
                _TcpSocket._clients.TryGetValue(ipAddress, out TcpClient client);
                Task clientTask = _TcpSocket.HandleClientAsync(client, Crane.IPAddress, _TcpSocket._cts.Token, state);
                state.IsEventSubscribed = true;
            }
            // èŽ·å–å½“å‰éœ€ä¸‹å‘ä»»åŠ¡å¹¶ç¼“å­˜åˆ°çŠ¶æ€ä¸­
            Dt_Task? task = GetTask(Crane);
            if (task != null && state.CurrentTask == null && state.StackerRunMode == (int)StackerModeEnum.Automatic && state.StackerError == (int)StackerErrorEnum.Normal && state.StackerTaskNum == 0)
            {
                SendStackerTask(task, state);
            }
            return;
        }
        /// <summary>
        ///  äº‹ä»¶ï¼šå®¢æˆ·ç«¯æ–­å¼€è¿žæŽ¥æ—¶è§¦å‘
        /// </summary>
        /// <param name="clientId"></param>
        /// <returns></returns>
        private Task<string?> _TcpSocket_RobotReceived(string clientId)
        {
            _socketStates.TryRemove(clientId, out _);
            return Task.FromResult<string?>(null);
        }
        /// <summary>
        /// äº‹ä»¶ï¼šæ”¶åˆ°æ¶ˆæ¯æ—¶è§¦å‘
        /// </summary>
        /// <param name="message"></param>
        /// <param name="isJson"></param>
        /// <param name="client"></param>
        /// <param name="state"></param>
        /// <returns></returns>
        private async Task<string?> _TcpSocket_MessageReceived(string message, bool isJson, TcpClient client, StackerSocketState state)
        {
            string messageLower = message.ToUpperInvariant();
            //区分堆垛机发送命令
            try
            {
            }
            catch
            {
            }
            return null;
        }
        /// <summary>
        /// å †åž›æœºä»»åŠ¡ä¸‹å‘
        /// </summary>
        private bool SendStackerTask(Dt_Task task, StackerSocketState state)
        {
            string message = "<";
            //获取对起始和终点位置进行解析
            message += ">";
            return _TcpSocket.SendToDeviceAsync(state.IPAddress, message).Result;
        }
        private Dt_Task? GetTask(StackerCraneDevice stackerCrane)
        {
            return null;
        }
    }
    public class StackerSocketState
    {
        public string IPAddress { get; set; } = string.Empty;
        /// <summary>
        /// æ˜¯å¦å·²è®¢é˜…消息事件
        /// </summary>
        public bool IsEventSubscribed { get; set; }
        /// <summary>
        /// å †åž›æœºå½“前任务号
        /// </summary>
        public int? StackerTaskNum { get; set; }
        /// <summary>
        /// å †åž›æœºè¿è¡Œæ¨¡å¼
        /// </summary>
        public int? StackerRunMode { get; set; }
        /// <summary>
        /// å †åž›æœºæ•…障状态
        /// </summary>
        public int? StackerError { get; set; }
        /// <summary>
        /// å †åž›æœºè®¾å¤‡ä¿¡æ¯
        /// </summary>
        public StackerCraneDevice? StackerCrane { get; set; }
        /// <summary>
        /// å–货位置
        /// </summary>
        public string? PickPosition { get; set; }
        /// <summary>
        /// æ”¾è´§ä½ç½®
        /// </summary>
        public string? PutPosition{ get; set; }
        /// <summary>
        /// å½“前任务
        /// </summary>
        public Dt_Task? CurrentTask { get; set; }
    }
    public enum StackerModeEnum
    {
        /// <summary>
        /// è‡ªåŠ¨æ¨¡å¼
        /// </summary>
        Automatic = 1,
        /// <summary>
        /// åœæ­¢æ¨¡å¼
        /// </summary>
        Unkonw = 2,
        /// <summary>
        /// æ‰‹åŠ¨æ¨¡å¼
        /// </summary>
        Manual = 3
    }
    public enum StackerErrorEnum
    {
        /// <summary>
        /// æ­£å¸¸
        /// </summary>
        Normal = 1,
        /// <summary>
        /// æ•…éšœ
        /// </summary>
        Fault = 2
    }
}
´úÂë¹ÜÀí/WCS/WCSServers/WIDESEAWCS_Tasks/StackerCraneJob/StackerCraneTaskCommand.cs
ÎļþÒÑɾ³ý
´úÂë¹ÜÀí/WCS/WCSServers/WIDESEAWCS_Tasks/TestJob.cs
ÎļþÒÑɾ³ý
´úÂë¹ÜÀí/WCS/WCSServices/WIDESEAWCS_Server/Controllers/Task/TaskController.cs
ÎļþÒÑɾ³ý
ÏîÄ¿×ÊÁÏ/ͨѶЭÒé/SIS±¨Îĸñʽ±¨ÎÄÑùÀýV1.6£¨´ø±¸×¢).xlsx
Binary files differ
ÏîÄ¿×ÊÁÏ/ͨѶЭÒé/»ù´¡Í¨Ñ¶ÖÐÒëЭÒé.pdf
Binary files differ
ÏîÄ¿×ÊÁÏ/ͨѶЭÒé/¶Ñ¶â»úͨѶÖÐÒëЭÒé.pdf
Binary files differ
ÏîÄ¿×ÊÁÏ/ͨѶЭÒé/ÊäËÍÏßͨѶÖÐÒëЭÒé.pdf
Binary files differ
ÏîÄ¿×ÊÁÏ/²¿Êð»·¾³¼°Èí¼þ¿ª·¢¼ò½é/net6.zip
Binary files differ
ÏîÄ¿×ÊÁÏ/²¿Êð»·¾³¼°Èí¼þ¿ª·¢¼ò½é/Èí¼þ¿ª·¢Åàѵ.pptx
Binary files differ