| | |
| | | /Code/WCS/WIDESEAWCS_S7Simulator/.vs/WIDESEAWCS_S7Simulator.slnx/v18/DocumentLayout.backup.json |
| | | /Code/WCS/WIDESEAWCS_S7Simulator/.vs/WIDESEAWCS_S7Simulator.slnx/v18/DocumentLayout.json |
| | | /.omc |
| | | /Code/WMS/WIDESEA_WMSServer/.omc |
| | | /Code/WMS/WIDESEA_WMSServer/.vs |
| | | /.omc |
| | | /Code/WCS/WIDESEAWCS_Server/.vs |
| | | Code/WCS/WIDESEAWCS_Server/.vs/WIDESEAWCS_Server/v18/DocumentLayout.json |
| | | Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_Server/appsettings.json |
| | | /Code/WMS/WIDESEA_WMSClient/.omc |
| | |
| | | { |
| | | "version": "1.0.0", |
| | | "lastScanned": 1774319550302, |
| | | "lastScanned": 1774488038530, |
| | | "projectRoot": "D:\\Git\\ShanMeiXinNengYuan", |
| | | "techStack": { |
| | | "languages": [], |
| | |
| | | "path": "Code", |
| | | "purpose": null, |
| | | "fileCount": 0, |
| | | "lastAccessed": 1774319550279, |
| | | "lastAccessed": 1774488038511, |
| | | "keyFiles": [] |
| | | }, |
| | | "项ç®èµæ": { |
| | | "path": "项ç®èµæ", |
| | | "purpose": null, |
| | | "fileCount": 0, |
| | | "lastAccessed": 1774319550280, |
| | | "lastAccessed": 1774488038512, |
| | | "keyFiles": [] |
| | | } |
| | | }, |
| | | "hotPaths": [ |
| | | { |
| | | "path": "Code\\WCS\\WIDESEAWCS_Client\\src\\views\\Index.vue", |
| | | "accessCount": 8, |
| | | "lastAccessed": 1774325288485, |
| | | "path": "Code\\WMS\\WIDESEA_WMSServer\\WIDESEA_StockService\\StockSerivce.cs", |
| | | "accessCount": 14, |
| | | "lastAccessed": 1774492937086, |
| | | "type": "file" |
| | | }, |
| | | { |
| | | "path": "Code\\WCS\\CLAUDE.md", |
| | | "accessCount": 4, |
| | | "lastAccessed": 1774319832508, |
| | | "type": "file" |
| | | }, |
| | | { |
| | | "path": "Code\\WMS\\CLAUDE.md", |
| | | "accessCount": 4, |
| | | "lastAccessed": 1774320014175, |
| | | "type": "file" |
| | | }, |
| | | { |
| | | "path": "Code\\WMS", |
| | | "accessCount": 2, |
| | | "lastAccessed": 1774319685208, |
| | | "type": "directory" |
| | | }, |
| | | { |
| | | "path": "Code\\WCS\\WIDESEAWCS_Client\\package.json", |
| | | "accessCount": 1, |
| | | "lastAccessed": 1774319589861, |
| | | "type": "file" |
| | | }, |
| | | { |
| | | "path": "Code\\WCS\\WIDESEAWCS_Server\\CLAUDE.md", |
| | | "accessCount": 1, |
| | | "lastAccessed": 1774319589915, |
| | | "type": "file" |
| | | }, |
| | | { |
| | | "path": "Code\\WCS\\WIDESEAWCS_Client\\README.md", |
| | | "accessCount": 1, |
| | | "lastAccessed": 1774319589977, |
| | | "type": "file" |
| | | }, |
| | | { |
| | | "path": "Code\\WCS\\WIDESEAWCS_Client\\src\\main.js", |
| | | "accessCount": 1, |
| | | "lastAccessed": 1774319604017, |
| | | "type": "file" |
| | | }, |
| | | { |
| | | "path": "Code\\WCS\\WIDESEAWCS_Client\\src\\router\\index.js", |
| | | "accessCount": 1, |
| | | "lastAccessed": 1774319604071, |
| | | "type": "file" |
| | | }, |
| | | { |
| | | "path": "Code\\WCS\\WIDESEAWCS_Server\\WIDESEAWCS_Server\\appsettings.json", |
| | | "accessCount": 1, |
| | | "lastAccessed": 1774319604091, |
| | | "type": "file" |
| | | }, |
| | | { |
| | | "path": "Code\\WCS\\WIDESEAWCS_Client\\src\\store\\index.js", |
| | | "accessCount": 1, |
| | | "lastAccessed": 1774319611661, |
| | | "type": "file" |
| | | }, |
| | | { |
| | | "path": "Code\\WCS\\WIDESEAWCS_Client\\src\\api\\http.js", |
| | | "accessCount": 1, |
| | | "lastAccessed": 1774319611675, |
| | | "type": "file" |
| | | }, |
| | | { |
| | | "path": "Code\\WMS\\WIDESEA_WMSClient\\package.json", |
| | | "accessCount": 1, |
| | | "lastAccessed": 1774319652164, |
| | | "type": "file" |
| | | }, |
| | | { |
| | | "path": "Code\\WMS\\WIDESEA_WMSClient\\vite.config.js", |
| | | "accessCount": 1, |
| | | "lastAccessed": 1774319656371, |
| | | "type": "file" |
| | | }, |
| | | { |
| | | "path": "Code\\WMS\\WIDESEA_WMSClient\\src\\main.js", |
| | | "accessCount": 1, |
| | | "lastAccessed": 1774319656381, |
| | | "path": "Code\\WMS\\WIDESEA_WMSServer\\WIDESEA_WMSServer\\appsettings.json", |
| | | "accessCount": 5, |
| | | "lastAccessed": 1774490361799, |
| | | "type": "file" |
| | | }, |
| | | { |
| | | "path": "Code\\WMS\\WIDESEA_WMSServer\\WIDESEA_WMSServer\\Program.cs", |
| | | "accessCount": 1, |
| | | "lastAccessed": 1774319656394, |
| | | "accessCount": 3, |
| | | "lastAccessed": 1774488093580, |
| | | "type": "file" |
| | | }, |
| | | { |
| | | "path": "Code\\WMS\\WIDESEA_WMSServer\\WIDESEA_WMSServer\\WIDESEA_WMSServer.csproj", |
| | | "accessCount": 1, |
| | | "lastAccessed": 1774319656456, |
| | | "lastAccessed": 1774488065335, |
| | | "type": "file" |
| | | }, |
| | | { |
| | | "path": "Code\\WMS\\WIDESEA_WMSServer\\WIDESEA_Core\\WIDESEA_Core.csproj", |
| | | "path": "Code\\WMS\\WIDESEA_WMSServer\\WIDESEA_StockService\\StockViewService.cs", |
| | | "accessCount": 1, |
| | | "lastAccessed": 1774319664837, |
| | | "lastAccessed": 1774492577060, |
| | | "type": "file" |
| | | }, |
| | | { |
| | | "path": "Code\\WMS\\WIDESEA_WMSServer\\WIDESEA_Core\\Extensions\\AutofacModuleRegister.cs", |
| | | "path": "Code\\WMS\\WIDESEA_WMSServer\\WIDESEA_StockService\\StockInfoService.cs", |
| | | "accessCount": 1, |
| | | "lastAccessed": 1774319668135, |
| | | "lastAccessed": 1774492577097, |
| | | "type": "file" |
| | | }, |
| | | { |
| | | "path": "Code\\WMS\\WIDESEA_WMSClient\\src\\router\\index.js", |
| | | "path": "Code\\WMS\\WIDESEA_WMSServer\\WIDESEA_StockService\\StockInfoDetailService.cs", |
| | | "accessCount": 1, |
| | | "lastAccessed": 1774319668167, |
| | | "lastAccessed": 1774492577122, |
| | | "type": "file" |
| | | }, |
| | | { |
| | | "path": "Code\\WMS\\WIDESEA_WMSServer\\WIDESEA_Core\\BaseServices\\IService.cs", |
| | | "path": "Code\\WMS\\WIDESEA_WMSServer\\WIDESEA_Core\\BaseServices\\ServiceBase.cs", |
| | | "accessCount": 1, |
| | | "lastAccessed": 1774319668191, |
| | | "lastAccessed": 1774492577619, |
| | | "type": "file" |
| | | }, |
| | | { |
| | | "path": "Code\\WMS\\WIDESEA_WMSServer\\WIDESEA_WMSServer\\Controllers\\Basic\\MaterielInfoController.cs", |
| | | "path": "Code\\WMS\\WIDESEA_WMSServer\\WIDESEA_IStockService\\IStockInfoService.cs", |
| | | "accessCount": 1, |
| | | "lastAccessed": 1774319671555, |
| | | "type": "file" |
| | | }, |
| | | { |
| | | "path": "Code\\WMS\\WIDESEA_WMSServer\\WIDESEA_IBasicService\\IMaterielInfoService.cs", |
| | | "accessCount": 1, |
| | | "lastAccessed": 1774319671580, |
| | | "type": "file" |
| | | }, |
| | | { |
| | | "path": "Code\\WMS\\WIDESEA_WMSServer\\WIDESEA_Model\\WIDESEA_Model.csproj", |
| | | "accessCount": 1, |
| | | "lastAccessed": 1774319671631, |
| | | "type": "file" |
| | | }, |
| | | { |
| | | "path": "Code\\WMS\\WIDESEA_WMSServer\\WIDESEA_WMSServer\\appsettings.json", |
| | | "accessCount": 1, |
| | | "lastAccessed": 1774319685049, |
| | | "type": "file" |
| | | }, |
| | | { |
| | | "path": "Code\\WMS\\WIDESEA_WMSServer\\WIDESEA_Core\\BaseController\\ApiBaseController.cs", |
| | | "accessCount": 1, |
| | | "lastAccessed": 1774319685114, |
| | | "lastAccessed": 1774492782997, |
| | | "type": "file" |
| | | } |
| | | ], |
| | |
| | | "WorkspaceRootPath": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WCS\\WIDESEAWCS_Server\\", |
| | | "Documents": [ |
| | | { |
| | | "AbsoluteMoniker": "D:0:0:{487FA45B-EA1A-4ACA-BB5B-0F6708F462C0}|WIDESEAWCS_Server\\WIDESEAWCS_Server.csproj|d:\\git\\shanmeixinnengyuan\\code\\wcs\\wideseawcs_server\\wideseawcs_server\\program.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}", |
| | | "RelativeMoniker": "D:0:0:{487FA45B-EA1A-4ACA-BB5B-0F6708F462C0}|WIDESEAWCS_Server\\WIDESEAWCS_Server.csproj|solutionrelative:wideseawcs_server\\program.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}" |
| | | }, |
| | | { |
| | | "AbsoluteMoniker": "D:0:0:{487FA45B-EA1A-4ACA-BB5B-0F6708F462C0}|WIDESEAWCS_Server\\WIDESEAWCS_Server.csproj|d:\\git\\shanmeixinnengyuan\\code\\wcs\\wideseawcs_server\\wideseawcs_server\\appsettings.json||{90A6B3A7-C1A3-4009-A288-E2FF89E96FA0}", |
| | | "RelativeMoniker": "D:0:0:{487FA45B-EA1A-4ACA-BB5B-0F6708F462C0}|WIDESEAWCS_Server\\WIDESEAWCS_Server.csproj|solutionrelative:wideseawcs_server\\appsettings.json||{90A6B3A7-C1A3-4009-A288-E2FF89E96FA0}" |
| | | }, |
| | | { |
| | | "AbsoluteMoniker": "D:0:0:{83F18A31-5983-4587-A0B2-414BF70E50B5}|WIDESEAWCS_TaskInfoService\\WIDESEAWCS_TaskInfoService.csproj|d:\\git\\shanmeixinnengyuan\\code\\wcs\\wideseawcs_server\\wideseawcs_taskinfoservice\\flows\\relocationtaskflowservice.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}", |
| | | "RelativeMoniker": "D:0:0:{83F18A31-5983-4587-A0B2-414BF70E50B5}|WIDESEAWCS_TaskInfoService\\WIDESEAWCS_TaskInfoService.csproj|solutionrelative:wideseawcs_taskinfoservice\\flows\\relocationtaskflowservice.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}" |
| | | }, |
| | |
| | | "DocumentGroups": [ |
| | | { |
| | | "DockedWidth": 200, |
| | | "SelectedChildIndex": 4, |
| | | "SelectedChildIndex": 3, |
| | | "Children": [ |
| | | { |
| | | "$type": "Bookmark", |
| | |
| | | "Name": "ST:0:0:{aa2115a1-9712-457b-9047-dbb71ca2cdd2}" |
| | | }, |
| | | { |
| | | "$type": "Bookmark", |
| | | "Name": "ST:0:0:{1c4feeaa-4718-4aa9-859d-94ce25d182ba}" |
| | | "$type": "Document", |
| | | "DocumentIndex": 0, |
| | | "Title": "Program.cs", |
| | | "DocumentMoniker": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WCS\\WIDESEAWCS_Server\\WIDESEAWCS_Server\\Program.cs", |
| | | "RelativeDocumentMoniker": "WIDESEAWCS_Server\\Program.cs", |
| | | "ToolTip": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WCS\\WIDESEAWCS_Server\\WIDESEAWCS_Server\\Program.cs", |
| | | "RelativeToolTip": "WIDESEAWCS_Server\\Program.cs", |
| | | "ViewState": "AgIAAB8AAAAAAAAAAAAAAD4AAAAuAAAAAAAAAA==", |
| | | "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|", |
| | | "WhenOpened": "2026-03-25T08:54:07.752Z", |
| | | "EditorCaption": "" |
| | | }, |
| | | { |
| | | "$type": "Document", |
| | | "DocumentIndex": 0, |
| | | "DocumentIndex": 1, |
| | | "Title": "appsettings.json", |
| | | "DocumentMoniker": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WCS\\WIDESEAWCS_Server\\WIDESEAWCS_Server\\appsettings.json", |
| | | "RelativeDocumentMoniker": "WIDESEAWCS_Server\\appsettings.json", |
| | | "ToolTip": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WCS\\WIDESEAWCS_Server\\WIDESEAWCS_Server\\appsettings.json", |
| | | "RelativeToolTip": "WIDESEAWCS_Server\\appsettings.json", |
| | | "ViewState": "AgIAAAAAAAAAAAAAAAAAABAAAAAEAAAAAAAAAA==", |
| | | "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.001642|", |
| | | "WhenOpened": "2026-03-25T08:50:00.052Z", |
| | | "EditorCaption": "" |
| | | }, |
| | | { |
| | | "$type": "Document", |
| | | "DocumentIndex": 2, |
| | | "Title": "RelocationTaskFlowService.cs", |
| | | "DocumentMoniker": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WCS\\WIDESEAWCS_Server\\WIDESEAWCS_TaskInfoService\\Flows\\RelocationTaskFlowService.cs", |
| | | "RelativeDocumentMoniker": "WIDESEAWCS_TaskInfoService\\Flows\\RelocationTaskFlowService.cs", |
| | | "ToolTip": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WCS\\WIDESEAWCS_Server\\WIDESEAWCS_TaskInfoService\\Flows\\RelocationTaskFlowService.cs", |
| | | "RelativeToolTip": "WIDESEAWCS_TaskInfoService\\Flows\\RelocationTaskFlowService.cs", |
| | | "ViewState": "AgIAAAAAAAAAAAAAAAAAABEAAABHAAAAAAAAAA==", |
| | | "ViewState": "AgIAAGkAAAAAAAAAAAAUwHAAAAAVAAAAAAAAAA==", |
| | | "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|", |
| | | "WhenOpened": "2026-03-19T09:35:02.468Z", |
| | | "EditorCaption": "" |
| | | }, |
| | | { |
| | | "$type": "Document", |
| | | "DocumentIndex": 2, |
| | | "DocumentIndex": 4, |
| | | "Title": "OutboundTaskFlowService.cs", |
| | | "DocumentMoniker": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WCS\\WIDESEAWCS_Server\\WIDESEAWCS_TaskInfoService\\Flows\\OutboundTaskFlowService.cs", |
| | | "RelativeDocumentMoniker": "WIDESEAWCS_TaskInfoService\\Flows\\OutboundTaskFlowService.cs", |
| | |
| | | "RelativeToolTip": "WIDESEAWCS_TaskInfoService\\Flows\\OutboundTaskFlowService.cs", |
| | | "ViewState": "AgIAAEMAAAAAAAAAAAAewEEAAAAiAAAAAAAAAA==", |
| | | "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|", |
| | | "WhenOpened": "2026-03-19T09:34:19.406Z" |
| | | "WhenOpened": "2026-03-19T09:34:19.406Z", |
| | | "EditorCaption": "" |
| | | }, |
| | | { |
| | | "$type": "Document", |
| | | "DocumentIndex": 4, |
| | | "DocumentIndex": 6, |
| | | "Title": "InboundTaskFlowService.cs", |
| | | "DocumentMoniker": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WCS\\WIDESEAWCS_Server\\WIDESEAWCS_TaskInfoService\\Flows\\InboundTaskFlowService.cs", |
| | | "RelativeDocumentMoniker": "WIDESEAWCS_TaskInfoService\\Flows\\InboundTaskFlowService.cs", |
| | |
| | | "RelativeToolTip": "WIDESEAWCS_TaskInfoService\\Flows\\InboundTaskFlowService.cs", |
| | | "ViewState": "AgIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==", |
| | | "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|", |
| | | "WhenOpened": "2026-03-19T09:34:14.627Z" |
| | | "WhenOpened": "2026-03-19T09:34:14.627Z", |
| | | "EditorCaption": "" |
| | | }, |
| | | { |
| | | "$type": "Document", |
| | | "DocumentIndex": 9, |
| | | "DocumentIndex": 11, |
| | | "Title": "ApiRouteCacheWarmupHostedService.cs", |
| | | "DocumentMoniker": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WCS\\WIDESEAWCS_Server\\WIDESEAWCS_Server\\HostedService\\ApiRouteCacheWarmupHostedService.cs", |
| | | "RelativeDocumentMoniker": "WIDESEAWCS_Server\\HostedService\\ApiRouteCacheWarmupHostedService.cs", |
| | |
| | | "RelativeToolTip": "WIDESEAWCS_Server\\HostedService\\ApiRouteCacheWarmupHostedService.cs", |
| | | "ViewState": "AgIAABoAAAAAAAAAAADwvzIAAAAdAAAAAAAAAA==", |
| | | "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|", |
| | | "WhenOpened": "2026-03-19T08:01:46.997Z" |
| | | "WhenOpened": "2026-03-19T08:01:46.997Z", |
| | | "EditorCaption": "" |
| | | }, |
| | | { |
| | | "$type": "Document", |
| | | "DocumentIndex": 10, |
| | | "DocumentIndex": 12, |
| | | "Title": "RedisServiceSetup.cs", |
| | | "DocumentMoniker": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WCS\\WIDESEAWCS_Server\\WIDESEAWCS_RedisService\\Extensions\\RedisServiceSetup.cs", |
| | | "RelativeDocumentMoniker": "WIDESEAWCS_RedisService\\Extensions\\RedisServiceSetup.cs", |
| | |
| | | "RelativeToolTip": "WIDESEAWCS_RedisService\\Extensions\\RedisServiceSetup.cs", |
| | | "ViewState": "AgIAADQAAAAAAAAAAAAqwCgAAAAAAAAAAAAAAA==", |
| | | "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|", |
| | | "WhenOpened": "2026-03-19T07:52:38.709Z" |
| | | "WhenOpened": "2026-03-19T07:52:38.709Z", |
| | | "EditorCaption": "" |
| | | }, |
| | | { |
| | | "$type": "Document", |
| | | "DocumentIndex": 11, |
| | | "DocumentIndex": 13, |
| | | "Title": "HttpClientHelper.cs", |
| | | "DocumentMoniker": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WCS\\WIDESEAWCS_Server\\WIDESEAWCS_Core\\Http\\HTTP\\HttpClientHelper.cs", |
| | | "RelativeDocumentMoniker": "WIDESEAWCS_Core\\Http\\HTTP\\HttpClientHelper.cs", |
| | |
| | | "RelativeToolTip": "WIDESEAWCS_Core\\Http\\HTTP\\HttpClientHelper.cs", |
| | | "ViewState": "AgIAAA4AAAAAAAAAAAAowBoAAABNAAAAAAAAAA==", |
| | | "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|", |
| | | "WhenOpened": "2026-03-19T07:48:09.389Z" |
| | | "WhenOpened": "2026-03-19T07:48:09.389Z", |
| | | "EditorCaption": "" |
| | | }, |
| | | { |
| | | "$type": "Document", |
| | | "DocumentIndex": 3, |
| | | "DocumentIndex": 5, |
| | | "Title": "TaskService.cs", |
| | | "DocumentMoniker": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WCS\\WIDESEAWCS_Server\\WIDESEAWCS_TaskInfoService\\TaskService.cs", |
| | | "RelativeDocumentMoniker": "WIDESEAWCS_TaskInfoService\\TaskService.cs", |
| | |
| | | "RelativeToolTip": "WIDESEAWCS_TaskInfoService\\TaskService.cs", |
| | | "ViewState": "AgIAAGQBAAAAAAAAAADwv3oBAABOAAAAAAAAAA==", |
| | | "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|", |
| | | "WhenOpened": "2026-03-19T01:42:07.337Z" |
| | | "WhenOpened": "2026-03-19T01:42:07.337Z", |
| | | "EditorCaption": "" |
| | | }, |
| | | { |
| | | "$type": "Document", |
| | | "DocumentIndex": 1, |
| | | "DocumentIndex": 3, |
| | | "Title": "CommonStackerCraneJob.cs", |
| | | "DocumentMoniker": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WCS\\WIDESEAWCS_Server\\WIDESEAWCS_Tasks\\StackerCraneJob\\CommonStackerCraneJob.cs", |
| | | "RelativeDocumentMoniker": "WIDESEAWCS_Tasks\\StackerCraneJob\\CommonStackerCraneJob.cs", |
| | |
| | | "RelativeToolTip": "WIDESEAWCS_Tasks\\StackerCraneJob\\CommonStackerCraneJob.cs", |
| | | "ViewState": "AgIAAEoAAAAAAAAAAAAQwF0AAAAzAAAAAAAAAA==", |
| | | "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|", |
| | | "WhenOpened": "2026-03-19T01:42:07.364Z" |
| | | "WhenOpened": "2026-03-19T01:42:07.364Z", |
| | | "EditorCaption": "" |
| | | }, |
| | | { |
| | | "$type": "Document", |
| | | "DocumentIndex": 7, |
| | | "DocumentIndex": 9, |
| | | "Title": "Sys_DictionaryService.cs", |
| | | "DocumentMoniker": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WCS\\WIDESEAWCS_Server\\WIDESEAWCS_SystemServices\\Sys_DictionaryService.cs", |
| | | "RelativeDocumentMoniker": "WIDESEAWCS_SystemServices\\Sys_DictionaryService.cs", |
| | |
| | | "RelativeToolTip": "WIDESEAWCS_SystemServices\\Sys_DictionaryService.cs", |
| | | "ViewState": "AgIAAAsAAAAAAAAAAAAIwFcAAAAQAAAAAAAAAA==", |
| | | "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|", |
| | | "WhenOpened": "2026-03-19T07:47:06.312Z" |
| | | "WhenOpened": "2026-03-19T07:47:06.312Z", |
| | | "EditorCaption": "" |
| | | }, |
| | | { |
| | | "$type": "Document", |
| | | "DocumentIndex": 6, |
| | | "DocumentIndex": 8, |
| | | "Title": "RobotWorkflowOrchestrator.cs", |
| | | "DocumentMoniker": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WCS\\WIDESEAWCS_Server\\WIDESEAWCS_Tasks\\RobotJob\\Workflow\\RobotWorkflowOrchestrator.cs", |
| | | "RelativeDocumentMoniker": "WIDESEAWCS_Tasks\\RobotJob\\Workflow\\RobotWorkflowOrchestrator.cs", |
| | | "ToolTip": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WCS\\WIDESEAWCS_Server\\WIDESEAWCS_Tasks\\RobotJob\\Workflow\\RobotWorkflowOrchestrator.cs", |
| | | "RelativeToolTip": "WIDESEAWCS_Tasks\\RobotJob\\Workflow\\RobotWorkflowOrchestrator.cs", |
| | | "ViewState": "AgIAADQAAAAAAAAAAAAkwC8AAAA1AAAAAAAAAA==", |
| | | "ViewState": "AgIAADQAAAAAAAAAAAA5wC8AAAA1AAAAAAAAAA==", |
| | | "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|", |
| | | "WhenOpened": "2026-03-18T09:21:38.852Z" |
| | | "WhenOpened": "2026-03-18T09:21:38.852Z", |
| | | "EditorCaption": "" |
| | | }, |
| | | { |
| | | "$type": "Document", |
| | | "DocumentIndex": 5, |
| | | "DocumentIndex": 7, |
| | | "Title": "RobotMessageHandler.cs", |
| | | "DocumentMoniker": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WCS\\WIDESEAWCS_Server\\WIDESEAWCS_Tasks\\RobotJob\\RobotMessageHandler.cs", |
| | | "RelativeDocumentMoniker": "WIDESEAWCS_Tasks\\RobotJob\\RobotMessageHandler.cs", |
| | | "ToolTip": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WCS\\WIDESEAWCS_Server\\WIDESEAWCS_Tasks\\RobotJob\\RobotMessageHandler.cs", |
| | | "RelativeToolTip": "WIDESEAWCS_Tasks\\RobotJob\\RobotMessageHandler.cs", |
| | | "ViewState": "AgIAABQAAAAAAAAAAADwvzwAAAAwAAAAAAAAAA==", |
| | | "ViewState": "AgIAABQAAAAAAAAAAAAwwDwAAAAwAAAAAAAAAA==", |
| | | "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|", |
| | | "WhenOpened": "2026-03-18T09:10:02.533Z" |
| | | "WhenOpened": "2026-03-18T09:10:02.533Z", |
| | | "EditorCaption": "" |
| | | }, |
| | | { |
| | | "$type": "Document", |
| | | "DocumentIndex": 8, |
| | | "DocumentIndex": 10, |
| | | "Title": "RobotJob.cs", |
| | | "DocumentMoniker": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WCS\\WIDESEAWCS_Server\\WIDESEAWCS_Tasks\\RobotJob\\RobotJob.cs", |
| | | "RelativeDocumentMoniker": "WIDESEAWCS_Tasks\\RobotJob\\RobotJob.cs", |
| | |
| | | "RelativeToolTip": "WIDESEAWCS_Tasks\\RobotJob\\RobotJob.cs", |
| | | "ViewState": "AgIAAEcAAAAAAAAAAAAmwDUAAAAPAAAAAAAAAA==", |
| | | "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|", |
| | | "WhenOpened": "2026-03-18T08:56:41.452Z" |
| | | "WhenOpened": "2026-03-18T08:56:41.452Z", |
| | | "EditorCaption": "" |
| | | } |
| | | ] |
| | | } |
| | |
| | | using Autofac; |
| | | using Autofac.Core; |
| | | using Autofac.Extensions.DependencyInjection; |
| | | using Magicodes.ExporterAndImporter.Excel.Utility.TemplateExport; |
| | | using Microsoft.AspNetCore.Builder; |
| | | using Microsoft.AspNetCore.Mvc.Controllers; |
| | | using Microsoft.AspNetCore.Mvc.ModelBinding.Validation; |
| | |
| | | using WIDESEAWCS_QuartzJob; |
| | | using WIDESEAWCS_QuartzJob.QuartzExtensions; |
| | | using WIDESEAWCS_QuartzJob.Seed; |
| | | using WIDESEAWCS_RedisService.Extensions; |
| | | using WIDESEAWCS_Server.Filter; |
| | | using WIDESEAWCS_Server.HostedService; |
| | | using WIDESEAWCS_Tasks.SocketServer; |
| | | using WIDESEAWCS_RedisService.Extensions; |
| | | using WIDESEAWCS_WCSServer.Filter; |
| | | |
| | | var builder = WebApplication.CreateBuilder(args); |
| | |
| | | // è¿æ ·å¯ä»¥åå°Microsoftæ¡æ¶æ¬èº«çè¯¦ç»æ¥å¿ï¼é¿å
è¿å¤çDebugæ¥å¿ |
| | | .MinimumLevel.Override("Microsoft", LogEventLevel.Information) |
| | | .WriteTo.Console() // æ·»å æ§å¶å°è¾åºæ¥æ¶å¨ï¼æ¥å¿å°æ¾ç¤ºå¨æ§å¶å°çªå£ä¸ |
| | | // æ·»å æä»¶è¾åºæ¥æ¶å¨ï¼å°æ¥å¿åå
¥æä»¶ç³»ç» |
| | | // æ·»å æä»¶è¾åºæ¥æ¶å¨ï¼å°æ¥å¿åå
¥æä»¶ç³»ç» |
| | | .WriteTo.File( |
| | | /*Path.Combine(AppContext.BaseDirectory, "Logs", "serilog-.log"),*/ // æå®æ¥å¿æä»¶ç宿´è·¯å¾ï¼åºç¨ç¨åºç®å½ + "Log"æä»¶å¤¹ + "serilog-æ¥æ.log" |
| | | "logs/serilog-.log", |
| | | rollingInterval: RollingInterval.Day, // 设置æ¥å¿æä»¶æå¤©æ»å¨ï¼æ¯å¤©çæä¸ä¸ªæ°çæ¥å¿æä»¶ |
| | | rollingInterval: RollingInterval.Day, // 设置æ¥å¿æä»¶æå¤©æ»å¨ï¼æ¯å¤©çæä¸ä¸ªæ°çæ¥å¿æä»¶ U1od4UGVsIKZG39S5Yak |
| | | retainedFileCountLimit: 30, // æå¤ä¿çæè¿30å¤©çæ¥å¿æä»¶ï¼è¶
è¿30天çæä»¶ä¼èªå¨å é¤ |
| | | shared: true); // å
许å¤ä¸ªè¿ç¨åæ¶åå
¥åä¸ä¸ªæ¥å¿æä»¶ï¼éç¨äºå¤å®ä¾é¨ç½²åºæ¯ |
| | | shared: true) // å
许å¤ä¸ªè¿ç¨åæ¶åå
¥åä¸ä¸ªæ¥å¿æä»¶ï¼éç¨äºå¤å®ä¾é¨ç½²åºæ¯ |
| | | .WriteTo.Seq( |
| | | serverUrl: "http://localhost:5341", |
| | | apiKey: "U1od4UGVsIKZG39S5Yak", // å¦Seqéè¦ApiKeyåé
ç½®çå®å¯é¥ |
| | | batchPostingLimit: 1000, // æ¹éåéæ°é |
| | | period: TimeSpan.FromSeconds(2) // åéé´é |
| | | ); |
| | | }); |
| | | |
| | | builder.Host.UseServiceProviderFactory(new AutofacServiceProviderFactory()).ConfigureContainer<ContainerBuilder>(builder => |
| | |
| | | <PackageReference Include="Serilog.AspNetCore" Version="8.0.3" /> |
| | | <PackageReference Include="Serilog.Settings.Configuration" Version="8.0.4" /> |
| | | <PackageReference Include="Serilog.Sinks.Console" Version="5.0.1" /> |
| | | <PackageReference Include="Serilog.Sinks.File" Version="5.0.0" /> |
| | | <PackageReference Include="Serilog.Sinks.File" Version="6.0.0" /> |
| | | <PackageReference Include="Serilog.Sinks.Seq" Version="9.0.0" /> |
| | | <PackageReference Include="Swashbuckle.AspNetCore" Version="6.5.0" /> |
| | | </ItemGroup> |
| | | |
| | |
| | | { |
| | | "urls": "http://*:9292", //webæå¡ç«¯å£ï¼å¦æç¨IISé¨ç½²ï¼æè¿ä¸ªå»æ |
| | | "Serilog": { |
| | | "MinimumLevel": { |
| | | "Default": "Information", |
| | | "Override": { |
| | | "Microsoft": "Information", |
| | | "Microsoft.AspNetCore": "Warning", |
| | | "Microsoft.AspNetCore.Routing": "Warning", |
| | | "Microsoft.AspNetCore.Mvc": "Warning", |
| | | "Microsoft.AspNetCore.Mvc.Infrastructure": "Warning", |
| | | "Microsoft.AspNetCore.Mvc.Filters": "Warning", |
| | | "Microsoft.AspNetCore.Mvc.ModelBinding": "Warning", |
| | | "Microsoft.EntityFrameworkCore": "Warning" |
| | | } |
| | | } |
| | | }, |
| | | "Logging": { |
| | | "LogLevel": { |
| | | "Default": "Information", |
| | |
| | | #region << ç æ¬ 注 é >> |
| | | |
| | | /*---------------------------------------------------------------- |
| | | * å½å空é´ï¼WIDESEAWCS_Tasks.ConveyorLineJob |
| | | * å建è
ï¼è¡ç«¥åº |
| | | * å建æ¶é´ï¼2024/8/2 16:13:36 |
| | | * çæ¬ï¼V1.0.0 |
| | | * æè¿°ï¼ |
| | | * |
| | | * ---------------------------------------------------------------- |
| | | * ä¿®æ¹äººï¼ |
| | | * ä¿®æ¹æ¶é´ï¼ |
| | | * çæ¬ï¼V1.0.1 |
| | | * ä¿®æ¹è¯´æï¼ |
| | | * |
| | | *----------------------------------------------------------------*/ |
| | | |
| | | #endregion << ç æ¬ 注 é >> |
| | | |
| | | using MapsterMapper; |
| | | using Microsoft.Extensions.Configuration; |
| | | using Quartz; |
| | |
| | | |
| | | namespace WIDESEAWCS_Tasks |
| | | { |
| | | /// <summary> |
| | | /// è¾é线任å¡ä½ä¸ï¼Quartz Jobï¼- æ ¸å¿æ§è¡é»è¾ |
| | | /// </summary> |
| | | /// <remarks> |
| | | /// Quartz 宿¶ä»»å¡ï¼è´è´£å¤çè¾é线çä»»å¡è°åº¦ã |
| | | /// ä½¿ç¨ [DisallowConcurrentExecution] ç¦æ¢å¹¶åæ§è¡ï¼ç¡®ä¿åä¸è®¾å¤çä»»å¡ä¸²è¡å¤çã |
| | | /// |
| | | /// æ ¸å¿èè´£ï¼ |
| | | /// 1. è·åè¾éçº¿çææå设å¤ä½ç½® |
| | | /// 2. å¹¶è¡å¤çæ¯ä¸ªå设å¤çæ¶æ¯ |
| | | /// 3. æ ¹æ®ä»»å¡ç¶æè°ç¨ç¸åºçè°åº¦æ¹æ³ |
| | | /// 4. å¤çå
¥åºååºåºä¸¤å¤§ç±»ä»»å¡ |
| | | /// |
| | | /// 该 Job éè¿ Parallel.For å¹¶è¡å¤çå¤ä¸ªå设å¤ï¼æé«å¤çæçã |
| | | /// </remarks> |
| | | [DisallowConcurrentExecution] |
| | | public class CommonConveyorLineNewJob : IJob |
| | | { |
| | | /// <summary> |
| | | /// ä»»å¡æå¡ |
| | | /// </summary> |
| | | private readonly ITaskService _taskService; |
| | | |
| | | /// <summary> |
| | | /// 任塿§è¡æç»æå¡ |
| | | /// </summary> |
| | | private readonly ITaskExecuteDetailService _taskExecuteDetailService; |
| | | |
| | | /// <summary> |
| | | /// è·¯ç±æå¡ |
| | | /// </summary> |
| | | private readonly IRouterService _routerService; |
| | | |
| | | /// <summary> |
| | | /// 对象æ å°å¨ |
| | | /// </summary> |
| | | private readonly IMapper _mapper; |
| | | |
| | | /// <summary> |
| | | /// è¾é线è°åº¦å¤çå¨ |
| | | /// </summary> |
| | | /// <remarks> |
| | | /// å°è£
äºè¾é线ä¸å¡é»è¾çå¤çæ¹æ³ã |
| | | /// </remarks> |
| | | private ConveyorLineDispatchHandler _conveyorLineDispatch; |
| | | |
| | | /// <summary> |
| | | /// HTTP 客æ·ç«¯å¸®å©ç±» |
| | | /// </summary> |
| | | /// <remarks> |
| | | /// ç¨äºè°ç¨ WMS ç³»ç»ç HTTP æ¥å£ã |
| | | /// </remarks> |
| | | private readonly HttpClientHelper _httpClientHelper; |
| | | |
| | | /// <summary> |
| | | /// æé 彿° |
| | | /// </summary> |
| | | /// <param name="taskService">任塿å¡</param> |
| | | /// <param name="taskExecuteDetailService">任塿§è¡æç»æå¡</param> |
| | | /// <param name="routerService">è·¯ç±æå¡</param> |
| | | /// <param name="mapper">对象æ å°å¨</param> |
| | | /// <param name="httpClientHelper">HTTP 客æ·ç«¯å¸®å©ç±»</param> |
| | | public CommonConveyorLineNewJob(ITaskService taskService, ITaskExecuteDetailService taskExecuteDetailService, IRouterService routerService, IMapper mapper, HttpClientHelper httpClientHelper) |
| | | { |
| | | _taskService = taskService; |
| | | _taskExecuteDetailService = taskExecuteDetailService; |
| | | _routerService = routerService; |
| | | _mapper = mapper; |
| | | _conveyorLineDispatch = new ConveyorLineDispatchHandler(_taskService, _taskExecuteDetailService, _routerService, _mapper); |
| | | _httpClientHelper = httpClientHelper; |
| | | |
| | | // åå§åè°åº¦å¤çå¨ |
| | | _conveyorLineDispatch = new ConveyorLineDispatchHandler(_taskService, _taskExecuteDetailService, _routerService, _mapper); |
| | | } |
| | | |
| | | /// <summary> |
| | | /// Quartz Job çæ§è¡å
¥å£ |
| | | /// </summary> |
| | | /// <remarks> |
| | | /// æ§è¡æµç¨ï¼ |
| | | /// 1. ä» JobDataMap è·åè¾é线设å¤ä¿¡æ¯ |
| | | /// 2. è·å该è¾éçº¿çææå设å¤ä½ç½®å表 |
| | | /// 3. å¹¶è¡å¤çæ¯ä¸ªå设å¤çæ¶æ¯ |
| | | /// 4. æ£æ¥æçä½ç½®ï¼ç¹å®é
ç½®çä½ç½®ï¼ |
| | | /// 5. æ ¹æ®ä»»å¡ç¶æååå°ç¸åºçå¤çæ¹æ³ |
| | | /// |
| | | /// å¹¶è¡å¤çæé«äºå¯¹å¤ç«å°è¾é线çå¤çæçã |
| | | /// </remarks> |
| | | /// <param name="context">Quartz ä½ä¸æ§è¡ä¸ä¸æ</param> |
| | | public Task Execute(IJobExecutionContext context) |
| | | { |
| | | try |
| | | { |
| | | // ä» JobDataMap è·åè¾é线设å¤åæ° |
| | | CommonConveyorLine conveyorLine = (CommonConveyorLine)context.JobDetail.JobDataMap.Get("JobParams"); |
| | | if (conveyorLine != null) |
| | | { |
| | | // è·å该è¾é线ä¸çææå设å¤ä½ç½®ç¼ç |
| | | List<string> childDeviceCodes = _routerService.QueryAllPositions(conveyorLine.DeviceCode); |
| | | if (childDeviceCodes == null || childDeviceCodes.Count == 0) |
| | | { |
| | | // 没æå设å¤ï¼ç´æ¥è¿å |
| | | Console.WriteLine($"è¾é线 {conveyorLine.DeviceCode} 没æå设å¤"); |
| | | return Task.CompletedTask; |
| | | } |
| | | |
| | | // å建并è¡é项 |
| | | // å建并è¡é项ï¼é嶿大并忰 |
| | | var parallelOptions = new ParallelOptions |
| | | { |
| | | MaxDegreeOfParallelism = Math.Min(childDeviceCodes.Count, Environment.ProcessorCount * 2), // åçéå¶å¹¶åæ° |
| | | // éå¶å¹¶åæ°ï¼åè®¾å¤æ°éå CPU æ ¸å¿æ°*2 çè¾å°å¼ |
| | | MaxDegreeOfParallelism = Math.Min(childDeviceCodes.Count, Environment.ProcessorCount * 2), |
| | | }; |
| | | |
| | | // å¹¶è¡å¤çæ¯ä¸ªåè®¾å¤ |
| | | Parallel.For(0, childDeviceCodes.Count, parallelOptions, i => |
| | | { |
| | | string childDeviceCode = childDeviceCodes[i]; |
| | | var correlationId = Guid.NewGuid().ToString("N"); |
| | | try |
| | | { |
| | | // 读å该ä½ç½®ç PLC å½ä»¤æ°æ® |
| | | ConveyorLineTaskCommandNew command = conveyorLine.ReadCustomer<ConveyorLineTaskCommandNew>(childDeviceCode); |
| | | |
| | | |
| | | // 妿å½ä»¤ä¸ºç©ºï¼è·³è¿ |
| | | if (command == null) |
| | | { |
| | | return; |
| | | } |
| | | |
| | | if(command.WCS_ACK == 1) |
| | | // 妿 WCS_ACK 为 1ï¼å
æ¸
é¤ï¼è¡¨ç¤ºå¤çè¿ä¸ä¸æ¬¡è¯·æ±ï¼ |
| | | if (command.WCS_ACK == 1) |
| | | conveyorLine.SetValue(ConveyorLineDBNameNew.WCS_ACK, 0, childDeviceCode); |
| | | |
| | | #region æ£æ¥ç¹å®ä½ç½®æ¯å¦ææç |
| | | |
| | | // ========== æ£æ¥ç¹å®ä½ç½®æ¯å¦ææç ========== |
| | | // ä»é
ç½®ä¸è¯»åéè¦æ£æ¥æççä½ç½®å表 |
| | | var checkPalletPositions = App.Configuration.GetSection("CheckPalletPositions") |
| | | .Get<List<CheckPalletPosition>>() ?? new List<CheckPalletPosition>(); |
| | | |
| | | // 妿å½å设å¤å¨æ£æ¥åè¡¨ä¸ |
| | | if (checkPalletPositions.Any(x => x.Code == childDeviceCode)) |
| | | { |
| | | // æ£æ¥è¾éçº¿ç¶æï¼æ¯å¦ææçï¼ |
| | | if (command.CV_State.ObjToBool()) |
| | | { |
| | | // æ£æ¥è¯¥ä½ç½®æ¯å¦å·²æä»»å¡ |
| | | var existingTask = _taskService.Repository.QueryFirst(x => x.TargetAddress == childDeviceCode); |
| | | if (existingTask.IsNullOrEmpty()) |
| | | { |
| | | // 没æä»»å¡ï¼å WMS 请æ±åºåºæçä»»å¡ |
| | | var position = checkPalletPositions.FirstOrDefault(x => x.Code == childDeviceCode); |
| | | var responseResult = _httpClientHelper.Post<WebResponseContent>("GetOutBoundTrayTaskAsync", new CreateTaskDto() |
| | | { |
| | |
| | | TargetAddress = childDeviceCode |
| | | }.Serialize()); |
| | | |
| | | // å¦æè¯·æ±æåï¼æ¥æ¶ WMS è¿åçä»»å¡ |
| | | if (responseResult.IsSuccess && responseResult.Data.Status) |
| | | { |
| | | var wmsTask = JsonSerializer.Deserialize<List<WMSTaskDTO>>(responseResult.Data.Data.Serialize()); |
| | |
| | | } |
| | | } |
| | | |
| | | #endregion |
| | | // ========== æ£æ¥ PLC_STB æ å¿ ========== |
| | | // åªæå½ PLC_STB 为 1 æ¶æå¤çä»»å¡ |
| | | if (command.PLC_STB != 1) return; |
| | | |
| | | if (command.PLC_STB != 1) return;//PLC_STB=1æ¶æå¤çä»»å¡ |
| | | |
| | | // ========== å¤çæ æçæ¡ç çæ
åµ ========== |
| | | // æ æçæ¡ç æ¶ï¼è¯·æ±åºåºä»»å¡ |
| | | if (command.Barcode.IsNullOrEmpty() || command.Barcode.Replace("\0", "") == "") |
| | | { |
| | | //æ æçå·æ¶ |
| | | _conveyorLineDispatch.RequestOutbound(conveyorLine, command, childDeviceCode); |
| | | return; |
| | | } |
| | | |
| | | // ========== å¤çå·²æä»»å¡å·çæ
åµ ========== |
| | | if (command.TaskNo > 0) |
| | | { |
| | | // æ¥è¯¢æ£å¨æ§è¡çä»»å¡ |
| | | Dt_Task task = _taskService.QueryExecutingConveyorLineTask(command.TaskNo, childDeviceCode); |
| | | if (!task.IsNullOrEmpty()) |
| | | { |
| | | // å¤çä»»å¡ç¶æ |
| | | // å¤çä»»å¡ç¶æï¼æ ¹æ®ç¶æååå°ä¸åæ¹æ³ï¼ |
| | | ProcessTaskState(conveyorLine, command, task, childDeviceCode); |
| | | //_conveyorLineDispatch.RequestInbound(conveyorLine, command, childDeviceCode); |
| | | return; |
| | | } |
| | | |
| | | } |
| | | } |
| | | catch (Exception innerEx) |
| | | { |
| | | // è®°å½å¼å¸¸ï¼ä½ä¸å½±åå
¶ä»å设å¤çå¤ç |
| | | Console.Error.WriteLine($"{DateTime.UtcNow:O} [{childDeviceCode}] CorrelationId={correlationId} {innerEx}"); |
| | | } |
| | | }); |
| | |
| | | } |
| | | catch (Exception ex) |
| | | { |
| | | // è®°å½æ´ä½å¼å¸¸ |
| | | Console.Error.WriteLine(ex); |
| | | } |
| | | return Task.CompletedTask; |
| | |
| | | /// <summary> |
| | | /// å¤çä»»å¡ç¶æ |
| | | /// </summary> |
| | | /// <param name="conveyorLine">è¾é线å®ä¾å¯¹è±¡</param> |
| | | /// <param name="command">读åç请æ±ä¿¡æ¯</param> |
| | | /// <param name="task">å设å¤ç¼å·</param> |
| | | /// <param name="childDeviceCode"></param> |
| | | /// <remarks> |
| | | /// æ ¹æ®ä»»å¡çå½åç¶æï¼è°ç¨ç¸åºçè°åº¦æ¹æ³ï¼ |
| | | /// - InExecuting: å
¥åºæ§è¡ä¸ -> è°ç¨ RequestInNextAddress |
| | | /// - OutExecuting: åºåºæ§è¡ä¸ -> æ ¹æ®æ¯å¦å°è¾¾ç®æ å°åè°ç¨å¯¹åºæ¹æ³ |
| | | /// - InFinish: å
¥åºå®æ -> è°ç¨ ConveyorLineInFinish |
| | | /// - OutFinish: åºåºå®æ -> è°ç¨ ConveyorLineOutFinish |
| | | /// </remarks> |
| | | /// <param name="conveyorLine">è¾é线设å¤å¯¹è±¡</param> |
| | | /// <param name="command">PLC å½ä»¤æ°æ®</param> |
| | | /// <param name="task">ä»»å¡å¯¹è±¡</param> |
| | | /// <param name="childDeviceCode">å设å¤ç¼ç </param> |
| | | private void ProcessTaskState(CommonConveyorLine conveyorLine, ConveyorLineTaskCommandNew command, Dt_Task task, string childDeviceCode) |
| | | { |
| | | // å®ä¹ç¶æå¸¸éï¼å¦æç±»ä¸å·²å®ä¹åå¯ç§»é¤ï¼ |
| | | const int InExecuting = (int)TaskInStatusEnum.Line_InExecuting; |
| | | const int OutExecuting = (int)TaskOutStatusEnum.Line_OutExecuting; |
| | | const int InFinish = (int)TaskInStatusEnum.InFinish; |
| | | const int OutFinish = (int)TaskOutStatusEnum.OutFinish; |
| | | // å®ä¹ä»»å¡ç¶æå¸¸é |
| | | const int InExecuting = (int)TaskInStatusEnum.Line_InExecuting; // å
¥åºæ§è¡ä¸ |
| | | const int OutExecuting = (int)TaskOutStatusEnum.Line_OutExecuting; // åºåºæ§è¡ä¸ |
| | | const int InFinish = (int)TaskInStatusEnum.InFinish; // å
¥åºå®æ |
| | | const int OutFinish = (int)TaskOutStatusEnum.OutFinish; // åºåºå®æ |
| | | |
| | | // è·åå½åä»»å¡ç¶æ |
| | | int state = task.TaskStatus; |
| | | |
| | | // 夿å½ååè®¾å¤æ¯å¦ä¸ºç®æ å°å |
| | | bool isTargetAddress = task.TargetAddress == childDeviceCode; |
| | | |
| | | // å¤çç¶æé»è¾ |
| | | // æ ¹æ®ç¶æååå¤ç |
| | | switch (state) |
| | | { |
| | | case InExecuting: |
| | | //if (isTargetAddress) |
| | | // _conveyorLineDispatch.ConveyorLineInFinish(conveyorLine, command, childDeviceCode); |
| | | //else |
| | | // å
¥åºæ§è¡ä¸ï¼è°ç¨ä¸ä¸å°åå¤ç |
| | | _conveyorLineDispatch.RequestInNextAddress(conveyorLine, command, childDeviceCode); |
| | | break; |
| | | |
| | | case OutExecuting: |
| | | // åºåºæ§è¡ä¸ |
| | | if (isTargetAddress) |
| | | // å°è¾¾ç®æ å°åï¼è°ç¨åºåºå®æ |
| | | _conveyorLineDispatch.ConveyorLineOutFinish(conveyorLine, command, childDeviceCode); |
| | | else |
| | | // æªå°è¾¾ç®æ å°åï¼è°ç¨åºåºä¸ä¸å°åå¤ç |
| | | _conveyorLineDispatch.RequestOutNextAddress(conveyorLine, command, childDeviceCode); |
| | | break; |
| | | |
| | | case InFinish: |
| | | // å
¥åºå®æ |
| | | _conveyorLineDispatch.ConveyorLineInFinish(conveyorLine, command, childDeviceCode); |
| | | break; |
| | | |
| | | case OutFinish: |
| | | // åºåºå®æ |
| | | _conveyorLineDispatch.ConveyorLineOutFinish(conveyorLine, command, childDeviceCode); |
| | | break; |
| | | } |
| | |
| | | using System; |
| | | using System.Collections.Generic; |
| | | using System.Linq; |
| | | using System.Text; |
| | | using System.Threading.Tasks; |
| | | |
| | | namespace WIDESEAWCS_Tasks |
| | | { |
| | | /// <summary> |
| | | /// æææº PLC å¯åå¨åç§°æä¸¾ |
| | | /// </summary> |
| | | /// <remarks> |
| | | /// å®ä¹æææºä¸ WCS éä¿¡æ¶ä½¿ç¨ç PLC å¯åå¨å°ååç§°ã |
| | | /// æææºæ¯ä¸ç§ç¨äºçµæ± ç产ç设å¤ï¼è´è´£åºå®/约æçµæ± æçã |
| | | /// è®¾å¤æä¸ä¸ä¸¤å±ç»æï¼æ¯å±é½æç¬ç«çç©æè¯·æ±ååºæä¿¡å·ã |
| | | /// </remarks> |
| | | public enum ConstraintMachineDBName |
| | | { |
| | | /// <summary> |
| | | /// ç©æµçº¿è¿è¡ä¿¡å· |
| | | /// </summary> |
| | | /// <remarks> |
| | | /// è¡¨ç¤ºç©æµçº¿ï¼è¿æ¥æææºçè¾éçº¿ï¼æ¯å¦å¨è¿è¡ã |
| | | /// </remarks> |
| | | LogisticsLineRunningSignal, |
| | | |
| | | /// <summary> |
| | | /// æææºè¿è¡ä¿¡å· |
| | | /// </summary> |
| | | /// <remarks> |
| | | /// è¡¨ç¤ºæææºæ¬èº«çè¿è¡ç¶æã |
| | | /// </remarks> |
| | | ConstraintMachineRunningSignal, |
| | | |
| | | /// <summary> |
| | | /// è¦æè¯·æ±-ä¸å± |
| | | /// </summary> |
| | | /// <remarks> |
| | | /// ä¸å±å·¥ä½åä¸çº§è®¾å¤ååºçåæè¯·æ±ã |
| | | /// éé¶å¼è¡¨ç¤ºä¸å±éè¦è¡¥å
ç©æã |
| | | /// </remarks> |
| | | MaterialRequestUpper, |
| | | |
| | | /// <summary> |
| | | /// ææçå¯åºæ-ä¸å± |
| | | /// </summary> |
| | | /// <remarks> |
| | | /// WCS åå
¥çä¿¡å·ï¼åç¥ä¸å±æçå¯ä»¥åºæã |
| | | /// </remarks> |
| | | ConstraintTrayOutputReadyUpper, |
| | | |
| | | /// <summary> |
| | | /// åºæè¯·æ±-ä¸å± |
| | | /// </summary> |
| | | /// <remarks> |
| | | /// ä¸å±å·¥ä½å®æå å·¥åååºçåºæè¯·æ±ã |
| | | /// éé¶å¼è¡¨ç¤ºææéè¦è¾åºã |
| | | /// </remarks> |
| | | OutputRequestUpper, |
| | | |
| | | /// <summary> |
| | | /// è¦æè¯·æ±-ä¸å± |
| | | /// </summary> |
| | | /// <remarks> |
| | | /// ä¸å±å·¥ä½åä¸çº§è®¾å¤ååºçåæè¯·æ±ã |
| | | /// éé¶å¼è¡¨ç¤ºä¸å±éè¦è¡¥å
ç©æã |
| | | /// </remarks> |
| | | MaterialRequestLower, |
| | | |
| | | /// <summary> |
| | | /// ææçå¯åºæ-ä¸å± |
| | | /// </summary> |
| | | /// <remarks> |
| | | /// WCS åå
¥çä¿¡å·ï¼åç¥ä¸å±æçå¯ä»¥åºæã |
| | | /// </remarks> |
| | | ConstraintTrayOutputReadyLower, |
| | | |
| | | /// <summary> |
| | | /// åºæè¯·æ±-ä¸å± |
| | | /// </summary> |
| | | /// <remarks> |
| | | /// ä¸å±å·¥ä½å®æå å·¥åååºçåºæè¯·æ±ã |
| | | /// éé¶å¼è¡¨ç¤ºææéè¦è¾åºã |
| | | /// </remarks> |
| | | OutputRequestLower |
| | | } |
| | | } |
| | | } |
| | |
| | | namespace WIDESEAWCS_Tasks |
| | | { |
| | | /// <summary> |
| | | /// æçä½ç½®æ£æ¥é
ç½®å®ä½ |
| | | /// </summary> |
| | | /// <remarks> |
| | | /// ç¨äºé
ç½®éè¦æ£æ¥æçä½ç½®çç«ç¹ä¿¡æ¯ã |
| | | /// å½ç³»ç»éè¦æ£æ¥ç¹å®ä½ç½®æ¯å¦ææçæ¶ä½¿ç¨æ¤é
ç½®ã |
| | | /// é
ç½®æ¥æºäº appsettings.json ä¸ç CheckPalletPositions èç¹ã |
| | | /// </remarks> |
| | | public class CheckPalletPosition |
| | | { |
| | | /// <summary> |
| | | /// å设å¤ç¼ç /ä½ç½®ç¼ç |
| | | /// </summary> |
| | | /// <remarks> |
| | | /// ç¨äºæ è¯éè¦æ£æ¥æççä½ç½®ç¹ã |
| | | /// </remarks> |
| | | public string Code { get; set; } = string.Empty; |
| | | |
| | | /// <summary> |
| | | /// ä»åº ID |
| | | /// </summary> |
| | | /// <remarks> |
| | | /// æ è¯æçæå¨çä»åºç¼å·ã |
| | | /// 1: ZYRB1 对åºçä»åº |
| | | /// 2: HPRB001 对åºçä»åº |
| | | /// 3: å
¶ä»ä»åº |
| | | /// </remarks> |
| | | public int WarehouseId { get; set; } = 0; |
| | | } |
| | | } |
| | |
| | | #region << ç æ¬ 注 é >> |
| | | /*---------------------------------------------------------------- |
| | | * å½å空é´ï¼WIDESEAWCS_Tasks.ConveyorLineJob |
| | | * å建è
ï¼è¡ç«¥åº |
| | | * å建æ¶é´ï¼2024/8/2 16:13:36 |
| | | * çæ¬ï¼V1.0.0 |
| | | * æè¿°ï¼ |
| | | * |
| | | * ---------------------------------------------------------------- |
| | | * ä¿®æ¹äººï¼ |
| | | * ä¿®æ¹æ¶é´ï¼ |
| | | * çæ¬ï¼V1.0.1 |
| | | * ä¿®æ¹è¯´æï¼ |
| | | * |
| | | *----------------------------------------------------------------*/ |
| | | #endregion << ç æ¬ 注 é >> |
| | | |
| | | using System; |
| | | using System.Collections.Generic; |
| | | using System.Linq; |
| | | using System.Text; |
| | | using System.Threading.Tasks; |
| | | |
| | | namespace WIDESEAWCS_Tasks |
| | | { |
| | | /// <summary> |
| | | /// è¾é线 PLC å¯åå¨åç§°æä¸¾ï¼æ°çï¼ |
| | | /// </summary> |
| | | /// <remarks> |
| | | /// å®ä¹è¾éçº¿ä¸ WCS éä¿¡æ¶ä½¿ç¨ç PLC å¯åå¨å°ååç§°ã |
| | | /// å
å«ä»»å¡å·ãå°åãç¶ææ å¿ãæ¡ç çåæ®µã |
| | | /// WCS éè¿è¿äºå¯åå¨ä¸ PLC 交äºï¼å®ç°ä»»å¡çä¸åãç¶æåæ¥åå®æç¡®è®¤ã |
| | | /// </remarks> |
| | | public enum ConveyorLineDBNameNew |
| | | { |
| | | /// <summary> |
| | | /// ä»»å¡å· |
| | | /// </summary> |
| | | /// <remarks> |
| | | /// PLC å WCS ä¹é´å
±äº«ç任塿 è¯å·ã |
| | | /// WCS ä¸å任塿¶åå
¥ï¼PLC 宿任å¡åä¿æã |
| | | /// </remarks> |
| | | TaskNo, |
| | | |
| | | /// <summary> |
| | | /// å¼å§å°å |
| | | /// å¼å§å°å/æºå°å |
| | | /// </summary> |
| | | /// <remarks> |
| | | /// ä»»å¡çèµ·å§ä½ç½®å°åã |
| | | /// ç¨äºå
¥åºä»»å¡æ¶è¡¨ç¤ºè´§ç©æ¥æºï¼åºåºä»»å¡æ¶è¡¨ç¤ºè´§ç©å½åä½ç½®ã |
| | | /// </remarks> |
| | | Source, |
| | | |
| | | /// <summary> |
| | | /// ç®çå°å |
| | | /// ç®æ å°å |
| | | /// </summary> |
| | | /// <remarks> |
| | | /// ä»»å¡çç®æ ä½ç½®å°åã |
| | | /// ç¨äºå
¥åºä»»å¡æ¶è¡¨ç¤ºè´§ç©åæ¾ä½ç½®ï¼åºåºä»»å¡æ¶è¡¨ç¤ºè´§ç©éè¾¾ä½ç½®ã |
| | | /// </remarks> |
| | | Target, |
| | | |
| | | /// <summary> |
| | | /// æçç±»å |
| | | /// </summary> |
| | | /// <remarks> |
| | | /// æ è¯æççè§æ ¼ç±»åã |
| | | /// </remarks> |
| | | BoxType, |
| | | |
| | | /// <summary> |
| | | /// 设å¤ç©ºé²ç¶æè¾éå¸¦ç¶æ |
| | | /// è¾é线空é²ç¶æ |
| | | /// </summary> |
| | | /// <remarks> |
| | | /// è¾é线å½åæ¯å¦ç©ºé²ã |
| | | /// é常ç¨äºå¤æè¾éçº¿ä¸æ¯å¦æè´§ç©æ£å¨ç§»å¨ã |
| | | /// </remarks> |
| | | CV_State, |
| | | |
| | | /// <summary> |
| | | /// è¾éæ
é代ç |
| | | /// è¾é线æ
é代ç |
| | | /// </summary> |
| | | /// <remarks> |
| | | /// PLC æ¥åçè®¾å¤æ
é代ç ã |
| | | /// 0 è¡¨ç¤ºæ æ
éï¼éé¶å¼è¡¨ç¤ºå
·ä½æ
éç±»åã |
| | | /// </remarks> |
| | | CV_ERRCode, |
| | | |
| | | /// <summary> |
| | | /// WCSä¸å宿æ¶ï¼è§¦å为1 |
| | | /// WCS ä¸å宿æ å¿ |
| | | /// </summary> |
| | | /// <remarks> |
| | | /// WCS ä¸åä»»å¡å®ææ¶ç½® 1ã |
| | | /// éç¥ PLC å¯ä»¥å¼å§å¤ç该任å¡ã |
| | | /// PLC 读åååºç«å³æ¸
餿¤æ å¿ã |
| | | /// </remarks> |
| | | WCS_STB, |
| | | |
| | | /// <summary> |
| | | /// WCSæ¶å°å®ææ¶ï¼è§¦å为1 |
| | | /// WCS åºçæ å¿ |
| | | /// </summary> |
| | | /// <remarks> |
| | | /// WCS æ¶å° PLC 请æ±ååå¤ç确认æ å¿ã |
| | | /// PLC ååºè¯·æ±åçå¾
WCS æ¤æ å¿ç½® 1ã |
| | | /// </remarks> |
| | | WCS_ACK, |
| | | |
| | | /// <summary> |
| | | /// 宿任塿¶ï¼è§¦å为1 |
| | | /// PLC ä»»å¡å®ææ å¿ |
| | | /// </summary> |
| | | /// <remarks> |
| | | /// PLC 宿任塿¶ç½® 1ã |
| | | /// éç¥ WCS ä»»å¡å·²å®æï¼å¯ä»¥è¿è¡åç»å¤çã |
| | | /// WCS 读åååºç«å³æ¸
餿¤æ å¿ã |
| | | /// </remarks> |
| | | PLC_STB, |
| | | |
| | | /// <summary> |
| | | /// æ¶å°ä»»å¡æ¶ï¼è§¦å为1 |
| | | /// PLC åºçæ å¿ |
| | | /// </summary> |
| | | /// <remarks> |
| | | /// PLC æ¶å° WCS å½ä»¤ååå¤ç确认æ å¿ã |
| | | /// WCS ä¸åå½ä»¤åçå¾
PLC æ¤æ å¿ç½® 1ã |
| | | /// </remarks> |
| | | PLC_ACK, |
| | | |
| | | /// <summary> |
| | | /// å
¥åºç«å°ï¼å°ä½å1 |
| | | /// PLC è¯·æ±æ å¿ |
| | | /// </summary> |
| | | /// <remarks> |
| | | /// PLC 主å¨è¯·æ±æå¡æ¶ç½® 1ã |
| | | /// é常ç¨äºå
¥åºç«å°ï¼è¡¨ç¤ºè´§ç©å·²å°ä½ï¼è¯·æ± WCS ä¸åä»»å¡ã |
| | | /// </remarks> |
| | | PLC_REQ, |
| | | |
| | | /// <summary> |
| | | /// WCSæ
é代ç |
| | | /// WCS é误代ç |
| | | /// </summary> |
| | | /// <remarks> |
| | | /// WCS æ¥åçä¸å¡é误代ç ã |
| | | /// ç¨äºæ è¯ä»»å¡æ§è¡è¿ç¨ä¸çä¸å¡é»è¾é误ã |
| | | /// </remarks> |
| | | WCS_ERRCode, |
| | | |
| | | /// <summary> |
| | | /// WCSç¹æ®å¤çæ è¯(æè½¬æ è¯ãå¼ºå¶æ¾è¡ã循ç¯ãç¹æ®ç³è¯·ãæ¯å¦å çãæ¯å¦å µå¡) |
| | | /// WCS ç¹æ®å¤çæ è¯ |
| | | /// </summary> |
| | | /// <remarks> |
| | | /// ç¨äºæ è¯ç¹æ®å¤çéæ±ï¼å
å«ä»¥ä¸ä½æ å¿ï¼ä»ä½ä½å°é«ä½ï¼ï¼ |
| | | /// - ä½0: æè½¬æ è¯ |
| | | /// - ä½1: å¼ºå¶æ¾è¡ |
| | | /// - ä½2: å¾ªç¯ |
| | | /// - ä½3: ç¹æ®ç³è¯· |
| | | /// - ä½4: æ¯å¦å ç |
| | | /// - ä½5: æ¯å¦å µå¡ |
| | | /// </remarks> |
| | | WCS_Special, |
| | | |
| | | /// <summary> |
| | | /// æå¨1ï¼èªå¨2 |
| | | /// 设å¤èªå¨æ¨¡å¼ |
| | | /// </summary> |
| | | /// <remarks> |
| | | /// æ è¯è®¾å¤çè¿è¡æ¨¡å¼ï¼ |
| | | /// - 1: æå¨æ¨¡å¼ |
| | | /// - 2: èªå¨æ¨¡å¼ |
| | | /// </remarks> |
| | | Equ_Auto, |
| | | |
| | | /// <summary> |
| | | /// å°¾çæ è¯ |
| | | /// å°¾ç/å°¾æ¿æ è¯ |
| | | /// </summary> |
| | | /// <remarks> |
| | | /// æ è¯å½åæçæ¯å¦ä¸ºæåä¸ä¸ªï¼å°¾çï¼ã |
| | | /// ç¨äºçµæ± ç产线çæåä¸éå·¥åºã |
| | | /// </remarks> |
| | | Last_pallet, |
| | | |
| | | /// <summary> |
| | | /// 容卿¡ç 1,å符æ°ç» |
| | | /// æçæ¡ç |
| | | /// </summary> |
| | | /// <remarks> |
| | | /// å卿ççæ¡ç ä¿¡æ¯ï¼22个å符ï¼ã |
| | | /// ç¨äºè´§ç©è¿½è¸ªååºä½ç®¡çã |
| | | /// </remarks> |
| | | Barcode |
| | | } |
| | | } |
| | |
| | | #region << ç æ¬ 注 é >> |
| | | /*---------------------------------------------------------------- |
| | | * å½å空é´ï¼WIDESEAWCS_Tasks.ConveyorLineJob |
| | | * å建è
ï¼è¡ç«¥åº |
| | | * å建æ¶é´ï¼2024/8/2 16:13:36 |
| | | * çæ¬ï¼V1.0.0 |
| | | * æè¿°ï¼ |
| | | * |
| | | * ---------------------------------------------------------------- |
| | | * ä¿®æ¹äººï¼ |
| | | * ä¿®æ¹æ¶é´ï¼ |
| | | * çæ¬ï¼V1.0.1 |
| | | * ä¿®æ¹è¯´æï¼ |
| | | * |
| | | *----------------------------------------------------------------*/ |
| | | #endregion << ç æ¬ 注 é >> |
| | | |
| | | using System; |
| | | using System.Collections.Generic; |
| | | using System.Linq; |
| | | using System.Runtime.InteropServices; |
| | | using System.Text; |
| | | using System.Threading.Tasks; |
| | | using WIDESEAWCS_QuartzJob.DeviceBase; |
| | | |
| | | namespace WIDESEAWCS_Tasks |
| | | { |
| | | /// <summary> |
| | | /// è¾é线 PLC éä¿¡å½ä»¤æ°æ®ç±»ï¼æ°çï¼ |
| | | /// </summary> |
| | | /// <remarks> |
| | | /// ç»§æ¿èª DeviceCommandï¼ç¨äºä¸è¾é线 PLC è¿è¡éä¿¡ã |
| | | /// å
å«ä»»å¡å·ãæº/ç®æ å°åãæçæ¡ç ãWCS/PLC åºçæ å¿çåæ®µã |
| | | /// WCS éè¿è¿äºåæ®µä¸ PLC 交äºï¼å®ç°ä»»å¡çä¸åãç¶æåæ¥åå®æç¡®è®¤ã |
| | | /// </remarks> |
| | | public class ConveyorLineTaskCommandNew : DeviceCommand |
| | | { |
| | | /// <summary> |
| | | /// ä»»å¡å· |
| | | /// </summary> |
| | | /// <remarks> |
| | | /// WCS åé
çä»»å¡å¯ä¸æ è¯å·ã |
| | | /// ç¨äºå¨ WCS å PLC ä¹é´å»ºç«ä»»å¡å¯¹åºçå
³èã |
| | | /// </remarks> |
| | | public short TaskNo { get; set; } |
| | | |
| | | /// <summary> |
| | | /// æºä½ç½® å¼å§å°å |
| | | /// æºä½ç½®/èµ·å§å°å |
| | | /// </summary> |
| | | public short Source { get; set; } |
| | | /// <remarks> |
| | | /// ä»»å¡çèµ·å§ä½ç½®å°åç¼ç ã |
| | | /// å
¥åºä»»å¡æ¶è¡¨ç¤ºè´§ç©æ¥èªåªä¸ªç«å°ï¼åºåºä»»å¡æ¶è¡¨ç¤ºè´§ç©å½åæå¨ä½ç½®ã |
| | | /// </remarks> |
| | | public short Source { get; set; } |
| | | |
| | | /// <summary> |
| | | /// ç®æ ä½ç½® |
| | | /// </summary> |
| | | /// <remarks> |
| | | /// ä»»å¡çç®æ ä½ç½®å°åç¼ç ã |
| | | /// å
¥åºä»»å¡æ¶è¡¨ç¤ºè´§ç©åå
¥åªä¸ªåºä½ï¼åºåºä»»å¡æ¶è¡¨ç¤ºè´§ç©éè¾¾åªä¸ªç«å°ã |
| | | /// </remarks> |
| | | public short Target { get; set; } |
| | | |
| | | /// <summary> |
| | | /// ç®±å |
| | | /// ç®±å/æçç±»å |
| | | /// </summary> |
| | | /// <remarks> |
| | | /// æ è¯æççè§æ ¼ç±»åï¼ç¨äºåºåä¸åçè´§ç©è½½ä½ã |
| | | /// </remarks> |
| | | public byte BoxType { get; set; } |
| | | |
| | | /// <summary> |
| | | /// è¾éçº¿ç¶æ 设å¤ç©ºé²ç¶æ |
| | | /// è¾éçº¿ç¶æ |
| | | /// </summary> |
| | | /// <remarks> |
| | | /// è¾é线ç空é²/å ç¨ç¶æã |
| | | /// ç¨äºå¤æè¾é线æ¯å¦å¯ä»¥æ¥åæ°ä»»å¡ã |
| | | /// </remarks> |
| | | public byte CV_State { get; set; } |
| | | |
| | | /// <summary> |
| | | /// è¾é线é误代ç |
| | | /// </summary> |
| | | /// <remarks> |
| | | /// PLC æ¥åçè®¾å¤æ
é代ç ã |
| | | /// 0 表示æ£å¸¸è¿è¡ï¼éé¶å¼è¡¨ç¤ºå
·ä½çæ
éç±»åã |
| | | /// </remarks> |
| | | public byte CV_ERRCode { get; set; } |
| | | |
| | | /// <summary> |
| | | /// WCS就绪æ å¿ WCSä¸å宿æ¶ï¼è§¦å为1 |
| | | /// WCS ä¸å宿æ å¿ |
| | | /// </summary> |
| | | /// <remarks> |
| | | /// WCS ä¸å任塿¶ç½® 1ï¼éç¥ PLC å¼å§æ§è¡ä»»å¡ã |
| | | /// PLC 读åååºç«å³æ¸
餿¤æ å¿ã |
| | | /// </remarks> |
| | | public byte WCS_STB { get; set; } |
| | | |
| | | /// <summary> |
| | | /// WCSåºçæ å¿ WCSæ¶å°å®ææ¶ï¼è§¦å为1 |
| | | /// WCS åºçæ å¿ |
| | | /// </summary> |
| | | /// <remarks> |
| | | /// WCS æ¶å° PLC 请æ±åçå夿 å¿ã |
| | | /// å½å¼ä¸º 1 æ¶è¡¨ç¤º WCS å·²æ¶å°è¯·æ±å¹¶å¤çã |
| | | /// </remarks> |
| | | public byte WCS_ACK { get; set; } |
| | | |
| | | /// <summary> |
| | | /// PLC就绪æ å¿ å®æä»»å¡æ¶ï¼è§¦å为1 |
| | | /// PLC ä»»å¡å®ææ å¿ |
| | | /// </summary> |
| | | /// <remarks> |
| | | /// PLC 宿任塿¶ç½® 1ï¼éç¥ WCS ä»»å¡å·²å®æã |
| | | /// WCS 读åååºæ¸
餿¤æ å¿ã |
| | | /// </remarks> |
| | | public byte PLC_STB { get; set; } |
| | | |
| | | /// <summary> |
| | | /// PLCåºçæ å¿ æ¶å°ä»»å¡æ¶ï¼è§¦å为1 |
| | | /// PLC åºçæ å¿ |
| | | /// </summary> |
| | | /// <remarks> |
| | | /// PLC æ¶å° WCS å½ä»¤åçå夿 å¿ã |
| | | /// å½å¼ä¸º 1 æ¶è¡¨ç¤º PLC å·²æ¶å°å½ä»¤ã |
| | | /// </remarks> |
| | | public byte PLC_ACK { get; set; } |
| | | |
| | | /// <summary> |
| | | /// PLCè¯·æ±æ å¿ å
¥åºç«å°ï¼å°ä½å1 |
| | | /// PLC è¯·æ±æ å¿ |
| | | /// </summary> |
| | | /// <remarks> |
| | | /// PLC 主å¨è¯·æ±æå¡æ¶ç½® 1ã |
| | | /// é常ç¨äºå
¥åºç«å°ï¼è¡¨ç¤ºè´§ç©å·²å°ä½å¯ä»¥å¼å§å¤çã |
| | | /// </remarks> |
| | | public byte PLC_REQ { get; set; } |
| | | |
| | | /// <summary> |
| | | /// WCSé误代ç |
| | | /// WCS é误代ç |
| | | /// </summary> |
| | | /// <remarks> |
| | | /// WCS æ¥åçä¸å¡é误代ç ã |
| | | /// ç¨äºæ è¯ä»»å¡æ§è¡è¿ç¨ä¸çä¸å¡é»è¾é误ã |
| | | /// </remarks> |
| | | public byte WCS_ERRCode { get; set; } |
| | | |
| | | /// <summary> |
| | | /// WCSç¹æ®æ å¿ (æè½¬æ è¯ãå¼ºå¶æ¾è¡ã循ç¯ãç¹æ®ç³è¯·ãæ¯å¦å çãæ¯å¦å µå¡) |
| | | /// WCS ç¹æ®æ å¿ |
| | | /// </summary> |
| | | /// <remarks> |
| | | /// ç¨äºæ è¯ç¹æ®å¤çéæ±ï¼å
å«å¤ä¸ªä½æ å¿ï¼ |
| | | /// - ä½0: æè½¬æ è¯ - æ¯å¦éè¦æè½¬æç |
| | | /// - ä½1: å¼ºå¶æ¾è¡ - 忽ç¥å¸¸è§æ£æ¥ç´æ¥æ¾è¡ |
| | | /// - ä½2: å¾ªç¯ - æ¯å¦å¾ªç¯æ§è¡ |
| | | /// - ä½3: ç¹æ®ç³è¯· - æ¯å¦æç¹æ®è¯·æ±éè¦å¤ç |
| | | /// - ä½4: æ¯å¦å ç - æ¯å¦éè¦å çå¤ç |
| | | /// - ä½5: æ¯å¦å µå¡ - æ¯å¦å¤äºå µå¡ç¶æ |
| | | /// </remarks> |
| | | public byte WCS_Special { get; set; } |
| | | |
| | | /// <summary> |
| | | /// 设å¤èªå¨æ¨¡å¼ æå¨1ï¼èªå¨2 |
| | | /// 设å¤èªå¨æ¨¡å¼ |
| | | /// </summary> |
| | | /// <remarks> |
| | | /// æ è¯è®¾å¤çè¿è¡æ¨¡å¼ï¼ |
| | | /// - 1: æå¨æ¨¡å¼ |
| | | /// - 2: èªå¨æ¨¡å¼ |
| | | /// </remarks> |
| | | public byte Equ_Auto { get; set; } |
| | | |
| | | /// <summary> |
| | | /// å°¾æ¿æ å¿ |
| | | /// å°¾æ¿/å°¾çæ å¿ |
| | | /// </summary> |
| | | /// <remarks> |
| | | /// æ è¯å½åæçæ¯å¦ä¸ºæåä¸ä¸ªï¼å°¾çï¼ã |
| | | /// ç¨äºçµæ± ç产线çæåä¸éå·¥åºï¼æ è®°æ´æ¹ä»»å¡çç»æã |
| | | /// </remarks> |
| | | public byte Last_pallet { get; set; } |
| | | |
| | | /// <summary> |
| | | /// æ¡ç ï¼22个åç¬¦ï¼ |
| | | /// æçæ¡ç ï¼22个åç¬¦ï¼ |
| | | /// </summary> |
| | | /// <remarks> |
| | | /// å卿ççæ¡ç ä¿¡æ¯ï¼ç¨äºè´§ç©è¿½è¸ªååºä½ç®¡çã |
| | | /// </remarks> |
| | | [DataLength(22)] |
| | | public string Barcode { get; set; } |
| | | } |
| | |
| | | #region << ç æ¬ 注 é >> |
| | | |
| | | /*---------------------------------------------------------------- |
| | | * å½å空é´ï¼WIDESEAWCS_Tasks.ConveyorLineJob |
| | | * å建è
ï¼è¡ç«¥åº |
| | | * å建æ¶é´ï¼2024/8/2 16:13:36 |
| | | * çæ¬ï¼V1.0.0 |
| | | * æè¿°ï¼ |
| | | * |
| | | * ---------------------------------------------------------------- |
| | | * ä¿®æ¹äººï¼ |
| | | * ä¿®æ¹æ¶é´ï¼ |
| | | * çæ¬ï¼V1.0.1 |
| | | * ä¿®æ¹è¯´æï¼ |
| | | * |
| | | *----------------------------------------------------------------*/ |
| | | |
| | | #endregion << ç æ¬ 注 é >> |
| | | |
| | | using MapsterMapper; |
| | | using WIDESEAWCS_Common.TaskEnum; |
| | | using WIDESEAWCS_Core; |
| | |
| | | |
| | | namespace WIDESEAWCS_Tasks |
| | | { |
| | | /// <summary> |
| | | /// è¾é线è°åº¦å¤çå¨ - å¤çè¾é线çåç§ä¸å¡è¯·æ± |
| | | /// </summary> |
| | | /// <remarks> |
| | | /// æ ¸å¿èè´£ï¼ |
| | | /// 1. å¤çè¾é线çå¿è·³ï¼ä¿æè¿æ¥ï¼ |
| | | /// 2. å¤çå
¥åºè¯·æ±ï¼PLC 请æ±å
¥åºä»»å¡ï¼ |
| | | /// 3. å¤çå
¥åºä¸ä¸å°åï¼ä»»å¡æ§è¡ä¸çå°åæ´æ°ï¼ |
| | | /// 4. å¤çå
¥åºå®æ |
| | | /// 5. å¤çåºåºè¯·æ± |
| | | /// 6. å¤çåºåºä¸ä¸å°å |
| | | /// 7. å¤çåºåºå®æ |
| | | /// |
| | | /// 该类æ¯è¾é线ä¸å¡é»è¾çæ ¸å¿ï¼æ ¹æ® PLC ç请æ±ç±»åè°ç¨ç¸åºçå¤çæ¹æ³ã |
| | | /// </remarks> |
| | | public class ConveyorLineDispatchHandler |
| | | { |
| | | /// <summary> |
| | | /// ä»»å¡æå¡ |
| | | /// </summary> |
| | | private readonly ITaskService _taskService; |
| | | |
| | | /// <summary> |
| | | /// 任塿§è¡æç»æå¡ |
| | | /// </summary> |
| | | private readonly ITaskExecuteDetailService _taskExecuteDetailService; |
| | | |
| | | /// <summary> |
| | | /// è·¯ç±æå¡ |
| | | /// </summary> |
| | | private readonly IRouterService _routerService; |
| | | |
| | | /// <summary> |
| | | /// 对象æ å°å¨ |
| | | /// </summary> |
| | | private readonly IMapper _mapper; |
| | | |
| | | /// <summary> |
| | | /// è¾é线任å¡è¿æ»¤å¨ |
| | | /// </summary> |
| | | /// <remarks> |
| | | /// ç¨äºæ¥è¯¢å¾
å¤çåæ§è¡ä¸çä»»å¡ã |
| | | /// </remarks> |
| | | private readonly ConveyorLineTaskFilter _taskFilter; |
| | | |
| | | /// <summary> |
| | | /// ç®æ å°åéæ©å¨ |
| | | /// </summary> |
| | | /// <remarks> |
| | | /// ç¨äºå¤çæææº/ææéæºç设å¤çä¸ä¸å±è¯·æ±ã |
| | | /// </remarks> |
| | | private readonly ConveyorLineTargetAddressSelector _targetAddressSelector; |
| | | |
| | | /// <summary> |
| | | /// æé 彿° |
| | | /// </summary> |
| | | /// <param name="taskService">任塿å¡</param> |
| | | /// <param name="taskExecuteDetailService">任塿§è¡æç»æå¡</param> |
| | | /// <param name="routerService">è·¯ç±æå¡</param> |
| | | /// <param name="mapper">对象æ å°å¨</param> |
| | | public ConveyorLineDispatchHandler(ITaskService taskService, ITaskExecuteDetailService taskExecuteDetailService, IRouterService routerService, IMapper mapper) |
| | | { |
| | | _taskService = taskService; |
| | |
| | | _routerService = routerService; |
| | | _mapper = mapper; |
| | | |
| | | // åå§åä»»å¡è¿æ»¤å¨åç®æ å°åéæ©å¨ |
| | | _taskFilter = new ConveyorLineTaskFilter(taskService); |
| | | _targetAddressSelector = new ConveyorLineTargetAddressSelector(); |
| | | } |
| | | |
| | | /// <summary> |
| | | /// å¿è·³å¤ç |
| | | /// å¤çè¾é线å¿è·³ |
| | | /// </summary> |
| | | /// <remarks> |
| | | /// 彿¶å° PLC çå¿è·³ä¿¡å·æ¶è°ç¨ã |
| | | /// æ¸
é¤ä»»å¡å·ï¼è¡¨ç¤ºå½åæ²¡ææ§è¡ä»»å¡ã |
| | | /// è¿æ¯ä¸ºäºä¿æä¸ PLC çè¿æ¥æ´»è·ã |
| | | /// </remarks> |
| | | /// <param name="conveyorLine">è¾é线设å¤å¯¹è±¡</param> |
| | | /// <param name="command">PLC å½ä»¤æ°æ®</param> |
| | | /// <param name="childDeviceCode">å设å¤ç¼ç </param> |
| | | public void HeartBeat(CommonConveyorLine conveyorLine, ConveyorLineTaskCommandNew command, string childDeviceCode) |
| | | { |
| | | // æ¸
é¤ä»»å¡å·ï¼è¡¨ç¤ºå½åç©ºé² |
| | | conveyorLine.SetValue(ConveyorLineDBNameNew.TaskNo, 0, childDeviceCode); |
| | | } |
| | | |
| | | /// <summary> |
| | | /// è¾é线请æ±å
¥åº |
| | | /// å¤çè¾é线å
¥åºè¯·æ± |
| | | /// </summary> |
| | | /// <remarks> |
| | | /// å½ PLC 请æ±å
¥åºä»»å¡æ¶è°ç¨ã |
| | | /// æµç¨ï¼ |
| | | /// 1. å WMS è¯·æ±æ°ä»»å¡ |
| | | /// 2. æ¥è¯¢å¾
å¤çä»»å¡ |
| | | /// 3. ä¸åä»»å¡å° PLC |
| | | /// 4. æ´æ°ä»»å¡ç¶æ |
| | | /// </remarks> |
| | | /// <param name="conveyorLine">è¾é线设å¤å¯¹è±¡</param> |
| | | /// <param name="command">PLC å½ä»¤æ°æ®</param> |
| | | /// <param name="childDeviceCode">å设å¤ç¼ç </param> |
| | | public void RequestInbound(CommonConveyorLine conveyorLine, ConveyorLineTaskCommandNew command, string childDeviceCode) |
| | | { |
| | | // å WMS è¯·æ±æ°ä»»å¡ï¼åºäºæ¡ç ï¼ |
| | | if (_taskFilter.RequestWmsTask(command.Barcode, childDeviceCode)) |
| | | { |
| | | // WMS è¿åæåï¼æ¥è¯¢å¾
å¤çä»»å¡ |
| | | Dt_Task? task = _taskFilter.QueryPendingTask(conveyorLine.DeviceCode, childDeviceCode); |
| | | if (task != null) |
| | | { |
| | | // å°ä»»å¡æ å°ä¸º PLC å½ä»¤ |
| | | ConveyorLineTaskCommandNew taskCommand = _mapper.Map<ConveyorLineTaskCommandNew>(task); |
| | | |
| | | // ç»§æ¿ WCS_ACK æ å¿ |
| | | taskCommand.WCS_ACK = command.WCS_ACK; |
| | | |
| | | // åéå½ä»¤å° PLC |
| | | conveyorLine.SendCommand(taskCommand, childDeviceCode); |
| | | |
| | | // æ´æ°ä»»å¡ç¶æå°ä¸ä¸é¶æ®µ |
| | | _taskService.UpdateTaskStatusToNext(task); |
| | | } |
| | | } |
| | | } |
| | | |
| | | /// <summary> |
| | | /// è¾é线请æ±å
¥åºä¸ä¸å°å |
| | | /// å¤çè¾é线å
¥åºä¸ä¸å°åè¯·æ± |
| | | /// </summary> |
| | | /// <remarks> |
| | | /// å½å
¥åºä»»å¡æ§è¡å°æä¸ªä¸é´ç«ç¹æ¶è°ç¨ã |
| | | /// æ ¹æ®ä¸ä¸å°å夿æ¯å¦éè¦ä¸æææº/ææéæºç设å¤äº¤äºã |
| | | /// </remarks> |
| | | /// <param name="conveyorLine">è¾é线设å¤å¯¹è±¡</param> |
| | | /// <param name="command">PLC å½ä»¤æ°æ®</param> |
| | | /// <param name="childDeviceCode">å设å¤ç¼ç </param> |
| | | public void RequestInNextAddress(CommonConveyorLine conveyorLine, ConveyorLineTaskCommandNew command, string childDeviceCode) |
| | | { |
| | | // æ¥è¯¢æ£å¨æ§è¡çä»»å¡ |
| | | Dt_Task? task = _taskFilter.QueryExecutingTask(command.TaskNo, childDeviceCode); |
| | | if (task == null) |
| | | { |
| | | return; |
| | | } |
| | | |
| | | // 妿䏿¯ç©ºæçä»»å¡ï¼å¤çç®æ å°åï¼ä¸æææº/ææéæºäº¤äºï¼ |
| | | if (task.TaskType != (int)TaskOutboundTypeEnum.OutEmpty) |
| | | { |
| | | _targetAddressSelector.HandleInboundNextAddress(conveyorLine, task.NextAddress, childDeviceCode); |
| | | } |
| | | |
| | | // æ´æ°ä»»å¡å½åä½ç½® |
| | | _ = _taskService.UpdatePosition(task.TaskNum, task.CurrentAddress); |
| | | |
| | | // 设置 WCS_STB æ å¿ï¼è¡¨ç¤º WCS å·²å¤ç |
| | | conveyorLine.SetValue(ConveyorLineDBNameNew.WCS_STB, 1, childDeviceCode); |
| | | } |
| | | |
| | | /// <summary> |
| | | /// è¾é线å
¥åºå®æ |
| | | /// å¤çè¾é线å
¥åºå®æ |
| | | /// </summary> |
| | | /// <remarks> |
| | | /// å½å
¥åºä»»å¡å®ææ¶è°ç¨ã |
| | | /// æ´æ°ä»»å¡ç¶æå¹¶åå¤ PLCã |
| | | /// </remarks> |
| | | /// <param name="conveyorLine">è¾é线设å¤å¯¹è±¡</param> |
| | | /// <param name="command">PLC å½ä»¤æ°æ®</param> |
| | | /// <param name="childDeviceCode">å设å¤ç¼ç </param> |
| | | public void ConveyorLineInFinish(CommonConveyorLine conveyorLine, ConveyorLineTaskCommandNew command, string childDeviceCode) |
| | | { |
| | | // æ¥è¯¢æ£å¨æ§è¡çä»»å¡ |
| | | Dt_Task? task = _taskFilter.QueryExecutingTask(command.TaskNo, childDeviceCode); |
| | | if (task != null) |
| | | { |
| | | // åå¤ ACK 确认 |
| | | conveyorLine.SetValue(ConveyorLineDBNameNew.WCS_ACK, 1, childDeviceCode); |
| | | |
| | | // æ´æ°ä»»å¡ç¶æå°ä¸ä¸é¶æ®µï¼é常æ¯å®æï¼ |
| | | WebResponseContent content = _taskService.UpdateTaskStatusToNext(task); |
| | | Console.Out.WriteLine(content.Serialize()); |
| | | } |
| | | } |
| | | |
| | | /// <summary> |
| | | /// è¾é线请æ±åºä¿¡æ¯ |
| | | /// å¤çè¾é线åºåºè¯·æ± |
| | | /// </summary> |
| | | /// <remarks> |
| | | /// å½ PLC 请æ±åºåºä»»å¡æ¶è°ç¨ã |
| | | /// æµç¨ï¼ |
| | | /// 1. æ¥è¯¢å¾
å¤çä»»å¡ |
| | | /// 2. ä¸åä»»å¡å° PLC |
| | | /// 3. æ´æ°ä»»å¡ç¶æ |
| | | /// </remarks> |
| | | /// <param name="conveyorLine">è¾é线设å¤å¯¹è±¡</param> |
| | | /// <param name="command">PLC å½ä»¤æ°æ®</param> |
| | | /// <param name="childDeviceCode">å设å¤ç¼ç </param> |
| | | public void RequestOutbound(CommonConveyorLine conveyorLine, ConveyorLineTaskCommandNew command, string childDeviceCode) |
| | | { |
| | | // æ¥è¯¢å¾
å¤çä»»å¡ |
| | | Dt_Task? task = _taskFilter.QueryPendingTask(conveyorLine.DeviceCode, childDeviceCode); |
| | | if (task != null) |
| | | { |
| | | // 设置任å¡å· |
| | | conveyorLine.SetValue(ConveyorLineDBNameNew.TaskNo, task.TaskNum, childDeviceCode); |
| | | |
| | | // 设置æçæ¡ç |
| | | conveyorLine.SetValue(ConveyorLineDBNameNew.Barcode, task.PalletCode, childDeviceCode); |
| | | |
| | | // è®¾ç½®ç®æ å°å |
| | | conveyorLine.SetValue(ConveyorLineDBNameNew.Target, task.NextAddress, childDeviceCode); |
| | | |
| | | // åå¤ ACK 确认 |
| | | conveyorLine.SetValue(ConveyorLineDBNameNew.WCS_ACK, 1, childDeviceCode); |
| | | |
| | | // æ´æ°ä»»å¡ç¶æ |
| | | _taskService.UpdateTaskStatusToNext(task); |
| | | } |
| | | } |
| | | |
| | | /// <summary> |
| | | /// è¾é线请æ±åºåºä¸ä¸å°å |
| | | /// å¤çè¾é线åºåºä¸ä¸å°åè¯·æ± |
| | | /// </summary> |
| | | /// <remarks> |
| | | /// å½åºåºä»»å¡æ§è¡å°æä¸ªä¸é´ç«ç¹æ¶è°ç¨ã |
| | | /// æ ¹æ®ä¸ä¸å°å夿æ¯å¦éè¦ä¸æææº/ææéæºç设å¤äº¤äºã |
| | | /// </remarks> |
| | | /// <param name="conveyorLine">è¾é线设å¤å¯¹è±¡</param> |
| | | /// <param name="command">PLC å½ä»¤æ°æ®</param> |
| | | /// <param name="childDeviceCode">å设å¤ç¼ç </param> |
| | | public void RequestOutNextAddress(CommonConveyorLine conveyorLine, ConveyorLineTaskCommandNew command, string childDeviceCode) |
| | | { |
| | | // æ¥è¯¢æ£å¨æ§è¡çä»»å¡ |
| | | Dt_Task? task = _taskFilter.QueryExecutingTask(command.TaskNo, childDeviceCode); |
| | | if (task == null) |
| | | { |
| | | return; |
| | | } |
| | | |
| | | // 妿䏿¯ç©ºæçä»»å¡ï¼å¤çç®æ å°å |
| | | if (task.TaskType != (int)TaskOutboundTypeEnum.OutEmpty) |
| | | { |
| | | _targetAddressSelector.HandleOutboundNextAddress(conveyorLine, task.NextAddress, childDeviceCode); |
| | | } |
| | | |
| | | // æ´æ°ä»»å¡å½åä½ç½® |
| | | _ = _taskService.UpdatePosition(task.TaskNum, task.CurrentAddress); |
| | | |
| | | |
| | | // åå¤ ACK 确认 |
| | | conveyorLine.SetValue(ConveyorLineDBNameNew.WCS_ACK, 1, childDeviceCode); |
| | | } |
| | | |
| | | /// <summary> |
| | | /// è¾é线åºåºå®æ |
| | | /// å¤çè¾é线åºåºå®æ |
| | | /// </summary> |
| | | /// <remarks> |
| | | /// å½åºåºä»»å¡å®ææ¶è°ç¨ã |
| | | /// æ´æ°ä»»å¡ç¶æå¹¶åå¤ PLCã |
| | | /// </remarks> |
| | | /// <param name="conveyorLine">è¾é线设å¤å¯¹è±¡</param> |
| | | /// <param name="command">PLC å½ä»¤æ°æ®</param> |
| | | /// <param name="childDeviceCode">å设å¤ç¼ç </param> |
| | | public void ConveyorLineOutFinish(CommonConveyorLine conveyorLine, ConveyorLineTaskCommandNew command, string childDeviceCode) |
| | | { |
| | | // æ¥è¯¢æ£å¨æ§è¡çä»»å¡ |
| | | Dt_Task? task = _taskFilter.QueryExecutingTask(command.TaskNo, childDeviceCode); |
| | | if (task != null) |
| | | { |
| | | // åå¤ ACK 确认 |
| | | conveyorLine.SetValue(ConveyorLineDBNameNew.WCS_ACK, 1, childDeviceCode); |
| | | |
| | | // æ´æ°ä»»å¡ç¶æå°ä¸ä¸é¶æ®µï¼é常æ¯å®æï¼ |
| | | WebResponseContent content = _taskService.UpdateTaskStatusToNext(task); |
| | | Console.Out.WriteLine(content.Serialize()); |
| | | } |
| | | } |
| | | } |
| | | } |
| | | |
| | |
| | | using WIDESEAWCS_QuartzJob; |
| | | using WIDESEAWCS_QuartzJob; |
| | | |
| | | namespace WIDESEAWCS_Tasks |
| | | { |
| | | /// <summary> |
| | | /// è¾é线设å¤è¯·æ±å¤çå¨ï¼å¤çæææº/ææéæºä¸ä¸å±è¯·æ±ã |
| | | /// è¾éçº¿ç®æ å°åéæ©å¨ - å¤çæææº/ææéæºçä¸ä¸å±è¯·æ± |
| | | /// </summary> |
| | | /// <remarks> |
| | | /// æ ¸å¿èè´£ï¼ |
| | | /// 1. å¤çå
¥åºåºæ¯çç®æ å°åéæ© |
| | | /// 2. å¤çåºåºåºæ¯çç®æ å°åéæ© |
| | | /// 3. å¤ææææºåææéæºçç©æè¯·æ±ç¶æ |
| | | /// 4. åè°è¾é线ä¸ä¸ä¸å±è®¾å¤ä¹é´çç©ææµè½¬ |
| | | /// |
| | | /// æææºåææéæºé½æä¸ä¸ä¸¤å±ç»æï¼ |
| | | /// æ¯å±é½æç¬ç«çç©æè¯·æ±ååºæä¿¡å·ï¼éè¦åå«å¤çã |
| | | /// </remarks> |
| | | public class ConveyorLineTargetAddressSelector |
| | | { |
| | | /// <summary> |
| | | /// æææºå称常é |
| | | /// </summary> |
| | | private const string ConstraintMachineName = "æææº"; |
| | | |
| | | /// <summary> |
| | | /// ææéæºå称常é |
| | | /// </summary> |
| | | private const string PinMachineName = "ææéæº"; |
| | | |
| | | // æææºç¹ä½ |
| | | /// <summary> |
| | | /// æææºå¯¹åºçç¹ä½ç¼ç å表 |
| | | /// </summary> |
| | | /// <remarks> |
| | | /// å½ç®æ å°åå¨è¿äºç¼ç 䏿¶ï¼è¡¨ç¤ºéè¦ä¸æææºäº¤äºã |
| | | /// </remarks> |
| | | private static readonly List<string> ConstraintMachineCodes = new List<string> { "10180", "20090" }; |
| | | // ææéæºç¹ä½ |
| | | |
| | | /// <summary> |
| | | /// ææéæºå¯¹åºçç¹ä½ç¼ç å表 |
| | | /// </summary> |
| | | /// <remarks> |
| | | /// å½ç®æ å°åå¨è¿äºç¼ç 䏿¶ï¼è¡¨ç¤ºéè¦ä¸ææéæºäº¤äºã |
| | | /// </remarks> |
| | | private static readonly List<string> PinMachineCodes = new List<string> { "10190", "20100" }; |
| | | |
| | | /// <summary> |
| | | /// å¤çå
¥åºåºæ¯çä¸ä¸å°åè¯·æ± |
| | | /// </summary> |
| | | /// <remarks> |
| | | /// å½å
¥åºä»»å¡æ§è¡å°æä¸ªä½ç½®æ¶è°ç¨æ¤æ¹æ³ã |
| | | /// å¤æç®æ è®¾å¤æ¯å¦éè¦ç©ææå¯ä»¥åºæã |
| | | /// </remarks> |
| | | /// <param name="conveyorLine">è¾é线设å¤å¯¹è±¡</param> |
| | | /// <param name="nextAddress">ä¸ä¸å°å/ç®æ 设å¤ç¼ç </param> |
| | | /// <param name="childDeviceCode">å½åå设å¤ç¼ç </param> |
| | | public void HandleInboundNextAddress(CommonConveyorLine conveyorLine, string nextAddress, string childDeviceCode) |
| | | { |
| | | // è°ç¨éç¨å¤çæ¹æ³ï¼isUpper = true 表示å¤çä¸å± |
| | | HandleDeviceRequest(conveyorLine, nextAddress, childDeviceCode, isUpper: true); |
| | | } |
| | | |
| | | /// <summary> |
| | | /// å¤çåºåºåºæ¯çä¸ä¸å°åè¯·æ± |
| | | /// </summary> |
| | | /// <remarks> |
| | | /// å½åºåºä»»å¡æ§è¡å°æä¸ªä½ç½®æ¶è°ç¨æ¤æ¹æ³ã |
| | | /// å¤æç®æ è®¾å¤æ¯å¦éè¦ç©ææå¯ä»¥åºæã |
| | | /// </remarks> |
| | | /// <param name="conveyorLine">è¾é线设å¤å¯¹è±¡</param> |
| | | /// <param name="nextAddress">ä¸ä¸å°å/ç®æ 设å¤ç¼ç </param> |
| | | /// <param name="childDeviceCode">å½åå设å¤ç¼ç </param> |
| | | public void HandleOutboundNextAddress(CommonConveyorLine conveyorLine, string nextAddress, string childDeviceCode) |
| | | { |
| | | // è°ç¨éç¨å¤çæ¹æ³ï¼isUpper = false 表示å¤çä¸å± |
| | | HandleDeviceRequest(conveyorLine, nextAddress, childDeviceCode, isUpper: false); |
| | | } |
| | | |
| | | /// <summary> |
| | | /// éç¨è®¾å¤è¯·æ±å¤çæ¹æ³ |
| | | /// </summary> |
| | | /// <remarks> |
| | | /// æ ¹æ®ç®æ å°åç±»åï¼æææº/ææéæºï¼è°ç¨ç¸åºçå¤çé»è¾ã |
| | | /// å¤çä¸ä¸å±è®¾å¤çç©æè¯·æ±ååºæåè°ã |
| | | /// </remarks> |
| | | /// <param name="conveyorLine">è¾é线设å¤å¯¹è±¡</param> |
| | | /// <param name="nextAddress">ä¸ä¸å°å/ç®æ 设å¤ç¼ç </param> |
| | | /// <param name="childDeviceCode">å½åå设å¤ç¼ç </param> |
| | | /// <param name="isUpper">æ¯å¦å¤çä¸å±ï¼true=ä¸å±ï¼false=ä¸å±ï¼</param> |
| | | private void HandleDeviceRequest(CommonConveyorLine conveyorLine, string nextAddress, string childDeviceCode, bool isUpper) |
| | | { |
| | | // è·åå
¨å±è®¾å¤å表 |
| | | var devices = Storage.Devices; |
| | | |
| | | // å¤æç®æ 设å¤ç±»å |
| | | if (ConstraintMachineCodes.Contains(nextAddress)) |
| | | { |
| | | // æææºå¤ç忝 |
| | | // æ¥æ¾æææºè®¾å¤ |
| | | ConstraintMachine? constraint = devices.OfType<ConstraintMachine>().FirstOrDefault(d => d.DeviceName == ConstraintMachineName); |
| | | if (constraint == null) |
| | | { |
| | | // æªæ¾å°æææºè®¾å¤ï¼ç´æ¥è¿å |
| | | return; |
| | | } |
| | | |
| | | // å¤çæææºçè¯·æ± |
| | | ProcessDeviceRequest( |
| | | conveyorLine, |
| | | childDeviceCode, |
| | | // è·åç©æè¯·æ±æ å¿ï¼ä¸å±æä¸å±ï¼ |
| | | getMaterialRequest: () => isUpper |
| | | ? constraint.GetValue<ConstraintMachineDBName, short>(ConstraintMachineDBName.MaterialRequestUpper) != 0 |
| | | : constraint.GetValue<ConstraintMachineDBName, short>(ConstraintMachineDBName.MaterialRequestLower) != 0, |
| | | // è·ååºæè¯·æ±æ å¿ï¼ä¸å±æä¸å±ï¼ |
| | | getOutputRequest: () => isUpper |
| | | ? constraint.GetValue<ConstraintMachineDBName, short>(ConstraintMachineDBName.OutputRequestUpper) != 0 |
| | | : constraint.GetValue<ConstraintMachineDBName, short>(ConstraintMachineDBName.OutputRequestLower) != 0, |
| | | // 设置è¾åºå°±ç»ªæ å¿ï¼ä¸å±æä¸å±ï¼ |
| | | setOutputReady: outputReq => |
| | | { |
| | | if (isUpper) |
| | |
| | | } |
| | | else if (PinMachineCodes.Contains(nextAddress)) |
| | | { |
| | | // ææéæºå¤ç忝 |
| | | // æ¥æ¾ææéæºè®¾å¤ |
| | | PinMachine? pinMachine = devices.OfType<PinMachine>().FirstOrDefault(d => d.DeviceName == PinMachineName); |
| | | if (pinMachine == null) |
| | | { |
| | | return; |
| | | } |
| | | |
| | | // å¤çææéæºçè¯·æ± |
| | | ProcessDeviceRequest( |
| | | conveyorLine, |
| | | childDeviceCode, |
| | | // è·åç©æè¯·æ±æ å¿ï¼ä¸å±æä¸å±ï¼ |
| | | getMaterialRequest: () => isUpper |
| | | ? pinMachine.GetValue<PinMachineDBName, short>(PinMachineDBName.MaterialRequestUpper) != 0 |
| | | : pinMachine.GetValue<PinMachineDBName, short>(PinMachineDBName.MaterialRequestLower) != 0, |
| | | // è·ååºæè¯·æ±æ å¿ï¼ä¸å±æä¸å±ï¼ |
| | | getOutputRequest: () => isUpper |
| | | ? pinMachine.GetValue<PinMachineDBName, short>(PinMachineDBName.OutputRequestUpper) != 0 |
| | | : pinMachine.GetValue<PinMachineDBName, short>(PinMachineDBName.OutputRequestLower) != 0, |
| | | // 设置è¾åºå°±ç»ªæ å¿ï¼ä¸å±æä¸å±ï¼ |
| | | setOutputReady: outputReq => |
| | | { |
| | | if (isUpper) |
| | |
| | | } |
| | | } |
| | | |
| | | /// <summary> |
| | | /// å¤ç设å¤è¯·æ±çæ ¸å¿é»è¾ |
| | | /// </summary> |
| | | /// <remarks> |
| | | /// æ ¹æ®ç©æè¯·æ±ååºæè¯·æ±çç¶æï¼ |
| | | /// - 妿æç©æè¯·æ±ï¼è®¾ç½®ç®æ å°åå¹¶åé ACK |
| | | /// - 妿æåºæè¯·æ±ï¼è®¾ç½®è®¾å¤çè¾åºå°±ç»ªæ å¿ |
| | | /// </remarks> |
| | | /// <param name="conveyorLine">è¾é线设å¤å¯¹è±¡</param> |
| | | /// <param name="childDeviceCode">å½åå设å¤ç¼ç </param> |
| | | /// <param name="getMaterialRequest">è·åç©æè¯·æ±ç¶æçå§æ</param> |
| | | /// <param name="getOutputRequest">è·ååºæè¯·æ±ç¶æçå§æ</param> |
| | | /// <param name="setOutputReady">设置è¾åºå°±ç»ªæ å¿çå§æ</param> |
| | | private static void ProcessDeviceRequest( |
| | | CommonConveyorLine conveyorLine, |
| | | string childDeviceCode, |
| | |
| | | Func<bool> getOutputRequest, |
| | | Action<bool> setOutputReady) |
| | | { |
| | | // è·åç©æè¯·æ±ç¶æ |
| | | bool materialReq = getMaterialRequest(); |
| | | |
| | | // è·ååºæè¯·æ±ç¶æ |
| | | bool outputReq = getOutputRequest(); |
| | | |
| | | // å¦æè®¾å¤éè¦ç©æ |
| | | if (materialReq) |
| | | { |
| | | // è®¾ç½®ç®æ å°å为 1ï¼è¡¨ç¤ºææè¿æ¥ï¼ |
| | | conveyorLine.SetValue(ConveyorLineDBNameNew.Target, 1, childDeviceCode); |
| | | |
| | | // åå¤ ACK ç¡®è®¤ä¿¡å· |
| | | conveyorLine.SetValue(ConveyorLineDBNameNew.WCS_ACK, 1, childDeviceCode); |
| | | } |
| | | else |
| | | { |
| | | // 设å¤ä¸éè¦ç©æï¼è®¾ç½®è¾åºå°±ç»ªæ å¿ |
| | | // éç¥è®¾å¤å¯ä»¥ç»§ç»åºæ |
| | | setOutputReady(outputReq); |
| | | } |
| | | } |
| | | } |
| | | } |
| | | |
| | |
| | | using WIDESEAWCS_ITaskInfoService; |
| | | using WIDESEAWCS_ITaskInfoService; |
| | | using WIDESEAWCS_Model.Models; |
| | | |
| | | namespace WIDESEAWCS_Tasks |
| | | { |
| | | /// <summary> |
| | | /// è¾é线任å¡è®¿é®å¨ï¼ç»ä¸å°è£
任塿¥è¯¢ä¸ WMS 请æ±ã |
| | | /// è¾é线任å¡è¿æ»¤å¨ - ç»ä¸å°è£
任塿¥è¯¢ä¸ WMS è¯·æ± |
| | | /// </summary> |
| | | /// <remarks> |
| | | /// æ ¸å¿èè´£ï¼ |
| | | /// 1. æ¥è¯¢è¾é线çå¾
å¤çä»»å¡ |
| | | /// 2. æ¥è¯¢æ£å¨æ§è¡çä»»å¡ |
| | | /// 3. å WMS è¯·æ±æ°ä»»å¡ |
| | | /// |
| | | /// 该类ä½ä¸ºä¸å¡å±ä¸ä»»å¡æå¡ä¹é´çä¸é´å±ï¼ |
| | | /// å°è£
äºå¸¸ç¨ç任塿¥è¯¢æä½ï¼æä¾ç®æ´çæ¥å£ç»è°ç¨æ¹ã |
| | | /// </remarks> |
| | | public class ConveyorLineTaskFilter |
| | | { |
| | | /// <summary> |
| | | /// 任塿å¡å®ä¾ |
| | | /// </summary> |
| | | /// <remarks> |
| | | /// ç¨äºè®¿é®æ°æ®åºä¸ç任塿°æ®ï¼ä»¥åä¸ WMS ç³»ç»äº¤äºã |
| | | /// </remarks> |
| | | private readonly ITaskService _taskService; |
| | | |
| | | /// <summary> |
| | | /// æé 彿° |
| | | /// </summary> |
| | | /// <param name="taskService">任塿å¡å®ä¾</param> |
| | | public ConveyorLineTaskFilter(ITaskService taskService) |
| | | { |
| | | _taskService = taskService; |
| | | } |
| | | |
| | | /// <summary> |
| | | /// æ¥è¯¢å¾
å¤ççè¾éçº¿ä»»å¡ |
| | | /// </summary> |
| | | /// <remarks> |
| | | /// æ ¹æ®è®¾å¤ç¼ç åå设å¤ç¼ç æ¥è¯¢ç¶æä¸º"å¾
å¤ç"çä»»å¡ã |
| | | /// ç¨äºå½ PLC 请æ±ä»»å¡æ¶ï¼WCS åæ°æ®åºæ¥è¯¢å¯ä¸åçä»»å¡ã |
| | | /// </remarks> |
| | | /// <param name="deviceCode">设å¤ç¼ç ï¼ä¸»è®¾å¤ï¼</param> |
| | | /// <param name="childDeviceCode">å设å¤ç¼ç ï¼ä½ç½®ç¼ç ï¼</param> |
| | | /// <returns>å¾
å¤ççä»»å¡å¯¹è±¡ï¼å¦ææ²¡æåè¿å null</returns> |
| | | public Dt_Task? QueryPendingTask(string deviceCode, string childDeviceCode) |
| | | { |
| | | return _taskService.QueryConveyorLineTask(deviceCode, childDeviceCode); |
| | | } |
| | | |
| | | /// <summary> |
| | | /// æ¥è¯¢æ£å¨æ§è¡çè¾éçº¿ä»»å¡ |
| | | /// </summary> |
| | | /// <remarks> |
| | | /// æ ¹æ®ä»»å¡å·åå设å¤ç¼ç æ¥è¯¢ç¶æä¸º"æ§è¡ä¸"çä»»å¡ã |
| | | /// ç¨äºè·è¸ªä»»å¡çæ§è¡è¿åº¦ã |
| | | /// </remarks> |
| | | /// <param name="taskNo">ä»»å¡å·</param> |
| | | /// <param name="childDeviceCode">å设å¤ç¼ç </param> |
| | | /// <returns>æ§è¡ä¸çä»»å¡å¯¹è±¡ï¼å¦ææ²¡æåè¿å null</returns> |
| | | public Dt_Task? QueryExecutingTask(int taskNo, string childDeviceCode) |
| | | { |
| | | return _taskService.QueryExecutingConveyorLineTask(taskNo, childDeviceCode); |
| | | } |
| | | |
| | | /// <summary> |
| | | /// å WMS è¯·æ±æ°ä»»å¡ |
| | | /// </summary> |
| | | /// <remarks> |
| | | /// å½è¾é线æè´§ç©å°è¾¾æ¶ï¼å WMS è¯·æ±æ°çä»»å¡ã |
| | | /// WMS 伿 ¹æ®ä»åºæ
åµåè°åº¦çç¥è¿ååéçä»»å¡ã |
| | | /// </remarks> |
| | | /// <param name="barcode">è´§ç©/æçæ¡ç </param> |
| | | /// <param name="childDeviceCode">请æ±çå设å¤ç¼ç </param> |
| | | /// <returns>è¯·æ±æ¯å¦æå</returns> |
| | | public bool RequestWmsTask(string barcode, string childDeviceCode) |
| | | { |
| | | return _taskService.RequestWMSTask(barcode, childDeviceCode).Status; |
| | |
| | | using System; |
| | | using System.Collections.Generic; |
| | | using System.Linq; |
| | | using System.Text; |
| | | using System.Threading.Tasks; |
| | | using WIDESEAWCS_QuartzJob.DeviceBase; |
| | | |
| | | namespace WIDESEAWCS_Tasks |
| | | { |
| | | /// <summary> |
| | | /// ææéæº PLC éä¿¡å½ä»¤æ°æ®ç±» |
| | | /// </summary> |
| | | /// <remarks> |
| | | /// ç»§æ¿èª DeviceCommandï¼ç¨äºä¸ææéæºè¿è¡ PLC éä¿¡ã |
| | | /// å
å«è®¾å¤çè¿è¡ç¶æãç©æè¯·æ±ãåºæè¯·æ±çä¿¡å·ã |
| | | /// </remarks> |
| | | public class PinMachineCommand : DeviceCommand |
| | | { |
| | | /// <summary> |
| | | /// ç©æµçº¿è¿è¡ä¿¡å· |
| | | /// </summary> |
| | | /// <remarks> |
| | | /// è¡¨ç¤ºç©æµçº¿ï¼è¿æ¥ææéæºçè¾éçº¿ï¼æ¯å¦å¨è¿è¡ã |
| | | /// </remarks> |
| | | public short LogisticsLineRunningSignal { get; set; } |
| | | |
| | | /// <summary> |
| | | /// ææéæºè¿è¡ä¿¡å· |
| | | /// </summary> |
| | | /// <remarks> |
| | | /// 表示ææéæºæ¬èº«çè¿è¡ç¶æã |
| | | /// </remarks> |
| | | public short PlugPinMachineRunningSignal { get; set; } |
| | | |
| | | /// <summary> |
| | | /// è¦æè¯·æ±-ä¸å± |
| | | /// </summary> |
| | | /// <remarks> |
| | | /// ä¸å±å·¥ä½åä¸çº§è®¾å¤ï¼å¦è¾é线ï¼ååºçåæè¯·æ±ã |
| | | /// éé¶å¼è¡¨ç¤ºéè¦è¡¥å
ç©æã |
| | | /// </remarks> |
| | | public short MaterialRequestUpper { get; set; } |
| | | |
| | | /// <summary> |
| | | /// åºæè¯·æ±-ä¸å± |
| | | /// </summary> |
| | | /// <remarks> |
| | | /// ä¸å±å·¥ä½å®æå å·¥åï¼åä¸çº§è®¾å¤ååºçåºæè¯·æ±ã |
| | | /// éé¶å¼è¡¨ç¤ºææéè¦è¾åºã |
| | | /// </remarks> |
| | | public short OutputRequestUpper { get; set; } |
| | | |
| | | /// <summary> |
| | | /// ææéçå¯åºæ-ä¸å± |
| | | /// </summary> |
| | | /// <remarks> |
| | | /// WCS åå¤ç»ä¸å±å·¥ä½ç确认信å·ã |
| | | /// åç¥ä¸å±æçå·²è¢«æ¥æ¶ï¼å¯ä»¥ç»§ç»åºæã |
| | | /// </remarks> |
| | | public short PlugPinTrayOutputReadyUpper { get; set; } |
| | | |
| | | /// <summary> |
| | | /// è¦æè¯·æ±-ä¸å± |
| | | /// </summary> |
| | | /// <remarks> |
| | | /// ä¸å±å·¥ä½åä¸çº§è®¾å¤ï¼å¦è¾é线ï¼ååºçåæè¯·æ±ã |
| | | /// éé¶å¼è¡¨ç¤ºéè¦è¡¥å
ç©æã |
| | | /// </remarks> |
| | | public short MaterialRequestLower { get; set; } |
| | | |
| | | /// <summary> |
| | | /// åºæè¯·æ±-ä¸å± |
| | | /// </summary> |
| | | /// <remarks> |
| | | /// ä¸å±å·¥ä½å®æå å·¥åï¼åä¸çº§è®¾å¤ååºçåºæè¯·æ±ã |
| | | /// éé¶å¼è¡¨ç¤ºææéè¦è¾åºã |
| | | /// </remarks> |
| | | public short OutputRequestLower { get; set; } |
| | | |
| | | /// <summary> |
| | | /// ææéçå¯åºæ-ä¸å± |
| | | /// </summary> |
| | | /// <remarks> |
| | | /// WCS åå¤ç»ä¸å±å·¥ä½ç确认信å·ã |
| | | /// åç¥ä¸å±æçå·²è¢«æ¥æ¶ï¼å¯ä»¥ç»§ç»åºæã |
| | | /// </remarks> |
| | | public short PlugPinTrayOutputReadyLower { get; set; } |
| | | } |
| | | } |
| | |
| | | namespace WIDESEAWCS_Tasks |
| | | namespace WIDESEAWCS_Tasks |
| | | { |
| | | /// <summary> |
| | | /// ææéæº PLC å¯åå¨åç§°æä¸¾ |
| | | /// </summary> |
| | | /// <remarks> |
| | | /// å®ä¹ææéæºä¸ WCS éä¿¡æ¶ä½¿ç¨ç PLC å¯åå¨å°ååç§°ã |
| | | /// ææéæºæ¯ä¸ç§ç¨äºçµæ± ç产ç设å¤ï¼è´è´£æéåæéæä½ã |
| | | /// è®¾å¤æä¸ä¸ä¸¤å±ç»æï¼æ¯å±é½æç¬ç«çç©æè¯·æ±ååºæä¿¡å·ã |
| | | /// </remarks> |
| | | public enum PinMachineDBName |
| | | { |
| | | /// <summary> |
| | | /// ç©æµçº¿è¿è¡ä¿¡å· |
| | | /// </summary> |
| | | /// <remarks> |
| | | /// è¡¨ç¤ºç©æµçº¿å½åæ¯å¦å¨è¿è¡ã |
| | | /// </remarks> |
| | | LogisticsLineRunningSignal, |
| | | |
| | | /// <summary> |
| | | /// ææéæºè¿è¡ä¿¡å· |
| | | /// </summary> |
| | | /// <remarks> |
| | | /// 表示ææéæºæ¬èº«æ¯å¦å¨è¿è¡ã |
| | | /// </remarks> |
| | | PlugPinMachineRunningSignal, |
| | | |
| | | /// <summary> |
| | | /// è¦æè¯·æ±-ä¸å± |
| | | /// </summary> |
| | | /// <remarks> |
| | | /// ä¸å±å·¥ä½éè¦åæç请æ±ä¿¡å·ã |
| | | /// å½å¼ä¸ºéé¶æ¶ï¼è¡¨ç¤ºä¸å±éè¦è¡¥å
ç©æã |
| | | /// </remarks> |
| | | MaterialRequestUpper, |
| | | |
| | | /// <summary> |
| | | /// åºæè¯·æ±-ä¸å± |
| | | /// </summary> |
| | | /// <remarks> |
| | | /// ä¸å±å·¥ä½å®æå å·¥åçåºæè¯·æ±ä¿¡å·ã |
| | | /// å½å¼ä¸ºéé¶æ¶ï¼è¡¨ç¤ºä¸å±ææéè¦è¾åºã |
| | | /// </remarks> |
| | | OutputRequestUpper, |
| | | |
| | | /// <summary> |
| | | /// ææéçå¯åºæ-ä¸å± |
| | | /// </summary> |
| | | /// <remarks> |
| | | /// WCS åå
¥çä¿¡å·ï¼åç¥ä¸å±æçå¯ä»¥åºæã |
| | | /// å½ WCS 设置为 1 æ¶ï¼è¡¨ç¤ºå
许ä¸å±åºæã |
| | | /// </remarks> |
| | | PlugPinTrayOutputReadyUpper, |
| | | |
| | | /// <summary> |
| | | /// è¦æè¯·æ±-ä¸å± |
| | | /// </summary> |
| | | /// <remarks> |
| | | /// ä¸å±å·¥ä½éè¦åæç请æ±ä¿¡å·ã |
| | | /// å½å¼ä¸ºéé¶æ¶ï¼è¡¨ç¤ºä¸å±éè¦è¡¥å
ç©æã |
| | | /// </remarks> |
| | | MaterialRequestLower, |
| | | |
| | | /// <summary> |
| | | /// åºæè¯·æ±-ä¸å± |
| | | /// </summary> |
| | | /// <remarks> |
| | | /// ä¸å±å·¥ä½å®æå å·¥åçåºæè¯·æ±ä¿¡å·ã |
| | | /// å½å¼ä¸ºéé¶æ¶ï¼è¡¨ç¤ºä¸å±ææéè¦è¾åºã |
| | | /// </remarks> |
| | | OutputRequestLower, |
| | | |
| | | /// <summary> |
| | | /// ææéçå¯åºæ-ä¸å± |
| | | /// </summary> |
| | | /// <remarks> |
| | | /// WCS åå
¥çä¿¡å·ï¼åç¥ä¸å±æçå¯ä»¥åºæã |
| | | /// å½ WCS 设置为 1 æ¶ï¼è¡¨ç¤ºå
许ä¸å±åºæã |
| | | /// </remarks> |
| | | PlugPinTrayOutputReadyLower |
| | | } |
| | | } |
| | | } |
| | |
| | | namespace WIDESEAWCS_Tasks.Workflow.Abstractions |
| | | { |
| | | /// <summary> |
| | | /// æºå¨äººæ¶æ¯è·¯ç±å
¥å£ãç¨äºæ¿æ¥ TcpSocketServer çæ¶æ¯äºä»¶ã |
| | | /// æºå¨äººæ¶æ¯è·¯ç±æ¥å£ - è´è´£æ¥æ¶æ¥èª TcpSocketServer çæ¶æ¯å¹¶ååç»åéçå¤çå¨ |
| | | /// </summary> |
| | | public interface IRobotMessageRouter |
| | | { |
| | | /// <summary> |
| | | /// å¤çæ¥æ¶å°çæ¶æ¯ |
| | | /// </summary> |
| | | /// <param name="message">åå§æ¶æ¯å符串</param> |
| | | /// <param name="isJson">æ¶æ¯æ¯å¦ä¸º JSON æ ¼å¼</param> |
| | | /// <param name="client">TCP 客æ·ç«¯è¿æ¥</param> |
| | | /// <param name="state">æºå¨äººå½åç¶æ</param> |
| | | /// <returns>ååºæ¶æ¯ï¼å¦ææ éåå¤åè¿å null</returns> |
| | | Task<string?> HandleMessageReceivedAsync(string message, bool isJson, TcpClient client, RobotSocketState state); |
| | | } |
| | | } |
| | | |
| | |
| | | using System.Net.Sockets; |
| | | using System.Net.Sockets; |
| | | |
| | | namespace WIDESEAWCS_Tasks.Workflow.Abstractions |
| | | { |
| | | /// <summary> |
| | | /// æºå¨äººåç¼å½ä»¤å¤çå¨ï¼pickfinished / putfinishedï¼ã |
| | | /// æºå¨äººåç¼å½ä»¤å¤ç卿¥å£ |
| | | /// </summary> |
| | | /// <remarks> |
| | | /// åç¼å½ä»¤æ¯æä»¥ç¹å®åç¼å¼å¤´çå½ä»¤ï¼åé¢è·ééå·åéçåæ°ã |
| | | /// å½åæ¯æï¼pickfinishedï¼åè´§å®æï¼ãputfinishedï¼æ¾è´§å®æï¼ |
| | | /// </remarks> |
| | | public interface IRobotPrefixCommandHandler |
| | | { |
| | | /// <summary> |
| | | /// æ£æ¥æ¶æ¯æ¯å¦ä¸ºåç¼å½ä»¤ |
| | | /// </summary> |
| | | /// <param name="message">æ¶æ¯å
容ï¼é常æ¯å°åå½¢å¼ï¼</param> |
| | | /// <returns>妿æ¯åç¼å½ä»¤è¿å true</returns> |
| | | bool IsPrefixCommand(string message); |
| | | |
| | | /// <summary> |
| | | /// å¤çåç¼å½ä»¤ |
| | | /// </summary> |
| | | /// <param name="message">åå§æ¶æ¯å
容</param> |
| | | /// <param name="state">æºå¨äººå½åç¶æ</param> |
| | | /// <param name="client">TCP 客æ·ç«¯è¿æ¥ï¼ç¨äºåéååº</param> |
| | | Task HandleAsync(string message, RobotSocketState state, TcpClient client); |
| | | } |
| | | } |
| | |
| | | namespace WIDESEAWCS_Tasks.Workflow.Abstractions |
| | | namespace WIDESEAWCS_Tasks.Workflow.Abstractions |
| | | { |
| | | /// <summary> |
| | | /// æºå¨äººç®åå½ä»¤å¤çå¨ï¼å¦è¿è¡ç¶æã模å¼åæ¢ãå
¨æµç¨å®æå½ä»¤ï¼ã |
| | | /// æºå¨äººç®åå½ä»¤å¤ç卿¥å£ |
| | | /// </summary> |
| | | /// <remarks> |
| | | /// ç®åå½ä»¤æ¯æä¸éè¦é¢å¤åæ°çç¶ææ´æ°å½ä»¤ï¼å¦è¿è¡ç¶æã模å¼åæ¢çã |
| | | /// ä¸åç¼å½ä»¤ï¼éè¦è§£æä½ç½®åæ°ï¼ç¸å¯¹ã |
| | | /// </remarks> |
| | | public interface IRobotSimpleCommandHandler |
| | | { |
| | | /// <summary> |
| | | /// å¤çç®åå½ä»¤ |
| | | /// </summary> |
| | | /// <param name="message">æ¶æ¯å
容ï¼å°åå½¢å¼ï¼</param> |
| | | /// <param name="state">æºå¨äººå½åç¶æï¼ä¼è¢«ä¿®æ¹ï¼</param> |
| | | /// <returns>æ¯å¦æåå¤çï¼æ æ³è¯å«çå½ä»¤è¿å false</returns> |
| | | Task<bool> HandleAsync(string message, RobotSocketState state); |
| | | } |
| | | } |
| | |
| | | namespace WIDESEAWCS_Tasks.Workflow.Abstractions |
| | | { |
| | | /// <summary> |
| | | /// æºå¨äººæµç¨ç¼æå¨ãè´è´£ RobotJob å
çç¶ææºåæ¯æ§è¡ã |
| | | /// æºå¨äººä»»å¡ç¼æå¨æ¥å£ - è´è´£ RobotJob ä¸çç¶ææºæµè½¬åæ§è¡æ¥éª¤ç¼æ |
| | | /// </summary> |
| | | public interface IRobotWorkflowOrchestrator |
| | | { |
| | | /// <summary> |
| | | /// æ§è¡ä»»å¡ç¼ææµç¨ |
| | | /// </summary> |
| | | /// <param name="latestState">æºå¨äººææ°ç¶æ</param> |
| | | /// <param name="task">å¾
æ§è¡çæºå¨äººä»»å¡</param> |
| | | /// <param name="ipAddress">æºå¨äºº IP å°å</param> |
| | | Task ExecuteAsync(RobotSocketState latestState, Dt_RobotTask task, string ipAddress); |
| | | } |
| | | } |
| | | |
| | |
| | | namespace WIDESEAWCS_Tasks.Workflow.Abstractions |
| | | { |
| | | /// <summary> |
| | | /// Socket 客æ·ç«¯ç½å
³ãç¨äºé离 Robot ä¸å¡å¯¹ TcpSocketServer çç´æ¥ä¾èµã |
| | | /// Socket 客æ·ç«¯ç½å
³æ¥å£ - å°è£
TcpSocketServer ç访é®ï¼ä½¿ä¸å¡å±ä¸ç´æ¥ä¾èµåºå±éä¿¡å®ç° |
| | | /// </summary> |
| | | /// <remarks> |
| | | /// 该æ¥å£æ¯ä¸å¡å±ä¸åºå± TCP éä¿¡ä¹é´çæ½è±¡å±ã |
| | | /// éè¿ä¾èµæ³¨å
¥åä½¿ç¨æ¥å£ï¼ä½¿ä¸å±ä»£ç ä¸ç´æ¥ä¾èµ TcpSocketServerï¼ |
| | | /// 便äºåç»æ¿æ¢éä¿¡å®ç°æè¿è¡åå
æµè¯ã |
| | | /// </remarks> |
| | | public interface ISocketClientGateway |
| | | { |
| | | /// <summary> |
| | | /// 弿¥åéæ¶æ¯å°æå®å®¢æ·ç«¯ |
| | | /// </summary> |
| | | /// <param name="clientId">ç®æ 客æ·ç«¯ç IP å°å</param> |
| | | /// <param name="message">è¦åéçæ¶æ¯å
容</param> |
| | | /// <returns>å鿝妿å</returns> |
| | | Task<bool> SendToClientAsync(string clientId, string message); |
| | | |
| | | /// <summary> |
| | | /// éè¿ TcpClient 对象åéæ¶æ¯ |
| | | /// </summary> |
| | | /// <remarks> |
| | | /// ä¸ SendToClientAsync çåºå«ï¼æ¤æ¹æ³ç´æ¥ä½¿ç¨ TcpClient å¯¹è±¡ï¼ |
| | | /// éç¨äºéè¦ååååºç»åéæ¹çåºæ¯ã |
| | | /// </remarks> |
| | | /// <param name="client">TCP 客æ·ç«¯è¿æ¥å¯¹è±¡</param> |
| | | /// <param name="message">è¦åéçæ¶æ¯å
容</param> |
| | | Task SendMessageAsync(TcpClient client, string message); |
| | | |
| | | /// <summary> |
| | | /// è·åææå·²è¿æ¥å®¢æ·ç«¯ç ID å表 |
| | | /// </summary> |
| | | /// <returns>客æ·ç«¯ IP å°åå表</returns> |
| | | IReadOnlyList<string> GetClientIds(); |
| | | |
| | | /// <summary> |
| | | /// 弿¥å¤ç客æ·ç«¯è¿æ¥çæ¶æ¯å¾ªç¯ |
| | | /// </summary> |
| | | /// <remarks> |
| | | /// å¯å¨åä¼æç»æ¥æ¶å®¢æ·ç«¯æ¶æ¯ï¼ç´å°è¿æ¥æå¼æåæ¶ä»¤ç被触åã |
| | | /// ç¨äºç®¡çå个客æ·ç«¯ççå½å¨æã |
| | | /// </remarks> |
| | | /// <param name="client">TCP 客æ·ç«¯è¿æ¥</param> |
| | | /// <param name="clientId">客æ·ç«¯æ è¯ï¼éå¸¸æ¯ IP å°åï¼</param> |
| | | /// <param name="cancellationToken">忶令ç</param> |
| | | /// <param name="robotCrane">æºå¨äººç¶æå¯¹è±¡</param> |
| | | Task HandleClientAsync(TcpClient client, string clientId, CancellationToken cancellationToken, RobotSocketState robotCrane); |
| | | } |
| | | } |
| | | |
| | |
| | | /// <summary> |
| | | /// æºæ¢°ææ¡ç çæå¨ - è´è´£çææçæ¡ç |
| | | /// </summary> |
| | | /// <remarks> |
| | | /// æ¡ç æ ¼å¼ï¼åç¼ï¼å¯éï¼+ æ¥æï¼yyyyMMddï¼+ æ¶é´ï¼HHmmssï¼+ éæºæ°ï¼100-999ï¼ |
| | | /// ä¾å¦ï¼TRAY20260326093045123 |
| | | /// </remarks> |
| | | public static class RobotBarcodeGenerator |
| | | { |
| | | /// <summary> |
| | | /// çææçæ¡ç |
| | | /// </summary> |
| | | /// <param name="prefix">æ¡ç åç¼ï¼é»è®¤ä¸ºç©º</param> |
| | | /// <returns>çæçæ¡ç å符串</returns> |
| | | /// <param name="prefix">æ¡ç åç¼ï¼é»è®¤ä¸ºç©ºå符串ï¼ä¾å¦ "TRAY"</param> |
| | | /// <returns>çæçæ¡ç åç¬¦ä¸²ï¼æ ¼å¼ï¼åç¼+æ¥æ+æ¶é´+éæºæ°</returns> |
| | | public static string GenerateTrayBarcode(string prefix = "") |
| | | { |
| | | // å½åæ¥æ |
| | | // è·åå½åæ¥æï¼æ ¼å¼å为 yyyyMMddï¼8使°åï¼ |
| | | // ä¾å¦ï¼20260326 |
| | | string datePart = DateTime.Now.ToString("yyyyMMdd"); |
| | | |
| | | // æ¶é´æ³ï¼æ¶åç§ï¼ |
| | | // è·åå½åæ¶é´ï¼æ¶åç§ï¼ï¼æ ¼å¼å为 HHmmssï¼6使°åï¼ |
| | | // ä¾å¦ï¼093045 表示 09:30:45 |
| | | string timePart = DateTime.Now.ToString("HHmmss"); |
| | | |
| | | // éæºæ° |
| | | // çæ3ä½éæºæ°ï¼èå´ 100-999ï¼ç¡®ä¿æ¡ç å¯ä¸æ§ |
| | | // ä½¿ç¨ Random.Shared è·å线ç¨å®å
¨çéæºæ°çæå¨ |
| | | string randomPart = Random.Shared.Next(100, 1000).ToString(); |
| | | |
| | | // ç»åï¼åç¼ + æ¥æ + æ¶é´ + éæºæ° |
| | | // ç»åææé¨åï¼åç¼ + æ¥æ + æ¶é´ + éæºæ° |
| | | // 妿åç¼ä¸ºç©ºï¼åç´æ¥è¿åæ¥æ+æ¶é´+éæºæ°çç»å |
| | | return prefix + datePart + timePart + randomPart; |
| | | } |
| | | } |
| | |
| | | using System.Collections.Concurrent; |
| | | using System.Net.Sockets; |
| | | using WIDESEAWCS_Core.LogHelper; |
| | | using WIDESEAWCS_QuartzJob; |
| | | using WIDESEAWCS_Tasks.SocketServer; |
| | | |
| | | namespace WIDESEAWCS_Tasks |
| | | { |
| | | /// <summary> |
| | | /// æºæ¢°æå®¢æ·ç«¯è¿æ¥ç®¡çå¨ - è´è´£TCP客æ·ç«¯è¿æ¥ç®¡çåäºä»¶è®¢é
|
| | | /// æºæ¢°æå®¢æ·ç«¯è¿æ¥ç®¡çå¨ - è´è´£ TCP 客æ·ç«¯è¿æ¥ç®¡çåäºä»¶è®¢é
|
| | | /// </summary> |
| | | /// <remarks> |
| | | /// æ ¸å¿èè´£ï¼ |
| | | /// 1. ç»´æ¤ä¸æºæ¢°æè®¾å¤ç TCP è¿æ¥ç¶æ |
| | | /// 2. ç¡®ä¿æ¯ä¸ªå®¢æ·ç«¯åªå¯å¨ä¸æ¬¡æ¶æ¯å¤çå¾ªç¯ |
| | | /// 3. 管ç客æ·ç«¯è¿æ¥/æå¼ççå½å¨æäºä»¶ |
| | | /// 4. æä¾åéæ¶æ¯å°å®¢æ·ç«¯çæ¥å£ |
| | | /// </remarks> |
| | | public class RobotClientManager |
| | | { |
| | | /// <summary> |
| | | /// TCP Socket æå¡å¨å®ä¾ï¼ç¨äºç®¡çææå®¢æ·ç«¯è¿æ¥ |
| | | /// </summary> |
| | | private readonly TcpSocketServer _tcpSocket; |
| | | |
| | | /// <summary> |
| | | /// æºæ¢°æç¶æç®¡çå¨ï¼ç¨äºè¯»å设å¤ç¶æ |
| | | /// </summary> |
| | | private readonly RobotStateManager _stateManager; |
| | | |
| | | // è·è¸ªå·²ç»å¯å¨ HandleClientAsync ç客æ·ç«¯ |
| | | /// <summary> |
| | | /// è·è¸ªå·²å¯å¨æ¶æ¯å¤çç客æ·ç«¯ï¼é¿å
éå¤å¯å¨ |
| | | /// </summary> |
| | | /// <remarks> |
| | | /// Key: 客æ·ç«¯ IP å°å |
| | | /// Value: æ¯å¦å·²å¯å¨ï¼true 表示已å¯å¨ï¼ |
| | | /// ä½¿ç¨ ConcurrentDictionary ä¿è¯çº¿ç¨å®å
¨ |
| | | /// </remarks> |
| | | private static readonly ConcurrentDictionary<string, bool> _handleClientStarted = new(); |
| | | |
| | | /// <summary> |
| | | /// äºä»¶è®¢é
æ å¿ï¼ç¡®ä¿ RobotReceived äºä»¶åªè®¢é
䏿¬¡ |
| | | /// </summary> |
| | | /// <remarks> |
| | | /// 使ç¨ååæä½ Interlocked.CompareExchange ä¿è¯å
¨å±åªè®¢é
䏿¬¡ |
| | | /// </remarks> |
| | | private static int _eventSubscribedFlag; |
| | | |
| | | /// <summary> |
| | | /// 客æ·ç«¯æå¼è¿æ¥æ¶è§¦åçäºä»¶ |
| | | /// </summary> |
| | | /// <remarks> |
| | | /// äºä»¶åæ°å
嫿å¼è¿æ¥çæºæ¢°æç¶æä¿¡æ¯ |
| | | /// </remarks> |
| | | public event EventHandler<RobotSocketState>? OnClientDisconnected; |
| | | |
| | | /// <summary> |
| | | /// æé 彿° |
| | | /// </summary> |
| | | /// <param name="tcpSocket">TCP Socket æå¡å¨å®ä¾</param> |
| | | /// <param name="stateManager">ç¶æç®¡çå¨å®ä¾</param> |
| | | public RobotClientManager(TcpSocketServer tcpSocket, RobotStateManager stateManager) |
| | | { |
| | | _tcpSocket = tcpSocket; |
| | |
| | | /// <summary> |
| | | /// ç¡®ä¿å®¢æ·ç«¯å·²è¿æ¥å¹¶è®¢é
æ¶æ¯äºä»¶ |
| | | /// </summary> |
| | | /// <param name="ipAddress">设å¤IPå°å</param> |
| | | /// <remarks> |
| | | /// è¿æ¯ RobotJob Execute æ¹æ³ä¸çæ ¸å¿æ£æ¥é»è¾ï¼ |
| | | /// 1. éªè¯å®¢æ·ç«¯æ¯å¦å¨çº¿ |
| | | /// 2. 订é
æå¼äºä»¶ï¼å
¨å±åªæ§è¡ä¸æ¬¡ï¼ |
| | | /// 3. ç¡®ä¿æ¶æ¯å¤ç循ç¯å·²å¯å¨ |
| | | /// 4. 鲿¢éå¤å¯å¨ HandleClientAsync |
| | | /// </remarks> |
| | | /// <param name="ipAddress">è®¾å¤ IP å°å</param> |
| | | /// <param name="robotCrane">æºå¨äººè®¾å¤ä¿¡æ¯</param> |
| | | /// <returns>客æ·ç«¯æ¯å¦å¯ç¨ï¼å·²è¿æ¥ä¸æ¶æ¯å¤çå·²å¯å¨ï¼</returns> |
| | | public bool EnsureClientSubscribed(string ipAddress, RobotCraneDevice robotCrane) |
| | | { |
| | | // æ£æ¥æ¯å¦æè¯¥å®¢æ·ç«¯è¿æ¥ |
| | | // ä» TCP æå¡å¨è·åææå·²è¿æ¥å®¢æ·ç«¯ç ID å表 |
| | | var clientIds = _tcpSocket.GetClientIds(); |
| | | |
| | | // æ£æ¥è¯¥ IP å°åç客æ·ç«¯æ¯å¦å·²è¿æ¥ |
| | | bool isClientConnected = clientIds.Contains(ipAddress); |
| | | |
| | | // 妿客æ·ç«¯æªè¿æ¥ |
| | | if (!isClientConnected) |
| | | { |
| | | // 客æ·ç«¯æªè¿æ¥ï¼æ¸
ç HandleClientAsync ç¶æ |
| | | // æ¸
ç该客æ·ç«¯ç HandleClientAsync å¯å¨æ å¿ |
| | | // ä»¥ä¾¿ä¸æ¬¡éè¿æ¶å¯ä»¥éæ°å¯å¨å¤ç |
| | | _handleClientStarted.TryRemove(ipAddress, out _); |
| | | return false; |
| | | } |
| | | |
| | | // 订é
䏿¬¡ robot äºä»¶ï¼å
¨å±ä¸æ¬¡ï¼- messageäºä»¶ç±RobotJob订é
|
| | | // 订é
䏿¬¡ RobotReceived äºä»¶ï¼å
¨å±åªè®¢é
䏿¬¡ï¼ |
| | | // ä½¿ç¨ Interlocked.CompareExchange å®ç°ååæä½ï¼ç¡®ä¿çº¿ç¨å®å
¨ |
| | | if (System.Threading.Interlocked.CompareExchange(ref _eventSubscribedFlag, 1, 0) == 0) |
| | | { |
| | | // ç»å®å®¢æ·ç«¯æå¼è¿æ¥çäºä»¶å¤ç |
| | | _tcpSocket.RobotReceived += OnRobotReceived; |
| | | Console.WriteLine($"[{DateTime.Now:yyyy-MM-dd HH:mm:ss}] æºå¨äººTCPæå¼äºä»¶å·²è®¢é
"); |
| | | // è®°å½æ¥å¿ï¼æ³¨æï¼æ¥å¿å
容为"客æ·ç«¯å·²æå¼è¿æ¥"ï¼å¯è½æ¯éççå 使æ¬ï¼ |
| | | QuartzLogger.Error($"客æ·ç«¯å·²æå¼è¿æ¥", robotCrane.DeviceName); |
| | | } |
| | | |
| | | // è·åTcpClient |
| | | // ä» TCP æå¡å¨ç客æ·ç«¯åå
¸ä¸è·å TcpClient 对象 |
| | | TcpClient? tcpClient = null; |
| | | _tcpSocket._clients.TryGetValue(ipAddress, out tcpClient); |
| | | |
| | | // 妿è·å失败ï¼è½ç¶ isClientConnected 为 trueï¼ä½å¯è½åå¨åå
¸ä¸åæ¥çæ
åµï¼ |
| | | if (tcpClient == null) |
| | | { |
| | | // isClientConnected为true使 æ³è·åtcpClientï¼å表å¯è½ä¸åæ¥ |
| | | // ç§»é¤å¯å¨æ å¿ï¼è¿å false 表示客æ·ç«¯ä¸å¯ç¨ |
| | | _handleClientStarted.TryRemove(ipAddress, out _); |
| | | return false; |
| | | } |
| | | |
| | | // æ£æ¥æ¯å¦å·²ç»ä¸ºè¿ä¸ªå®¢æ·ç«¯å¯å¨è¿ HandleClientAsync |
| | | // æ£æ¥æ¯å¦å·²ç»ä¸ºè¿ä¸ªå®¢æ·ç«¯å¯å¨è¿æ¶æ¯å¤çå¾ªç¯ |
| | | bool alreadyStarted = _handleClientStarted.TryGetValue(ipAddress, out _); |
| | | |
| | | // 妿尿ªå¯å¨ï¼åå¯å¨æ¶æ¯å¤çå¾ªç¯ |
| | | if (!alreadyStarted) |
| | | { |
| | | Console.WriteLine($"[{DateTime.Now:yyyy-MM-dd HH:mm:ss}] å¯å¨å®¢æ·ç«¯æ¶æ¯å¤ç: {ipAddress}"); |
| | | // è®°å½æ¥å¿ |
| | | QuartzLogger.Error($"å¯å¨å®¢æ·ç«¯æ¶æ¯å¤ç", robotCrane.DeviceName); |
| | | |
| | | // éæ°è·åææ°ç state 对象 |
| | | // è·åææ°çç¶æå¯¹è±¡ |
| | | var latestStateForSubscribe = _stateManager.GetState(ipAddress); |
| | | if (latestStateForSubscribe != null) |
| | | { |
| | | // æ 记为已å¯å¨ |
| | | // æ 记为已å¯å¨ï¼é²æ¢éå¤å¯å¨ |
| | | _handleClientStarted[ipAddress] = true; |
| | | |
| | | // 弿¥å¯å¨å®¢æ·ç«¯æ¶æ¯å¤çå¾ªç¯ |
| | | // ä½¿ç¨ TaskContinuationOptions.OnlyOnFaulted æè·å¼å¸¸æ
åµ |
| | | _ = _tcpSocket.HandleClientAsync(tcpClient, robotCrane.IPAddress, _tcpSocket._cts.Token, latestStateForSubscribe) |
| | | .ContinueWith(t => |
| | | { |
| | | // 妿å¤çåºç°å¼å¸¸ |
| | | if (t.IsFaulted) |
| | | { |
| | | // è®°å½é误æ¥å¿ |
| | | QuartzLogger.Error($"çå¬å®¢æ·ç«¯æ¶æ¯äºä»¶å¼å¸¸", robotCrane.DeviceName); |
| | | Console.WriteLine($"[{DateTime.Now:yyyy-MM-dd HH:mm:ss}] HandleClientAsync error: {t.Exception?.GetBaseException().Message}"); |
| | | // åçé误æ¶ï¼ç§»é¤å¯å¨æ å¿ï¼å
è®¸ä¸æ¬¡éè¯ |
| | | _handleClientStarted.TryRemove(ipAddress, out _); |
| | | } |
| | | }, TaskContinuationOptions.OnlyOnFaulted); |
| | | |
| | | // æ´æ° IsEventSubscribed ç¶æ |
| | | // å®å
¨æ´æ°ç¶æï¼æ 记为已订é
æ¶æ¯äºä»¶ |
| | | _stateManager.TryUpdateStateSafely(ipAddress, s => |
| | | { |
| | | s.IsEventSubscribed = true; |
| | |
| | | } |
| | | } |
| | | |
| | | // è¿å true 表示客æ·ç«¯å¯ç¨ |
| | | return true; |
| | | } |
| | | |
| | | /// <summary> |
| | | /// äºä»¶ï¼å®¢æ·ç«¯æå¼è¿æ¥æ¶è§¦å |
| | | /// äºä»¶å¤çï¼å®¢æ·ç«¯æå¼è¿æ¥æ¶è°ç¨ |
| | | /// </summary> |
| | | /// <remarks> |
| | | /// è§¦åæ¶æºï¼å½ TCP æå¡å¨æ£æµå°å®¢æ·ç«¯æå¼è¿æ¥æ¶ |
| | | /// å¤çé»è¾ï¼ |
| | | /// 1. æ¸
ç HandleClientAsync å¯å¨æ å¿ |
| | | /// 2. é置设å¤ç¶æï¼åæ¶è®¢é
ãæ¸
é¤å¨ä½åç¶æï¼ |
| | | /// 3. 触å OnClientDisconnected äºä»¶éç¥ä¸å± |
| | | /// </remarks> |
| | | /// <param name="clientId">æå¼è¿æ¥ç客æ·ç«¯ IP å°å</param> |
| | | /// <returns>åºå®è¿å nullï¼å 为æ¯äºä»¶å¤çå¨èéçæ£çæ¶æ¯å¤çå¨</returns> |
| | | private Task<string?> OnRobotReceived(string clientId) |
| | | { |
| | | // 客æ·ç«¯æå¼è¿æ¥ï¼æ¸
ç HandleClientAsync å¯å¨æ å¿ |
| | | // ç§»é¤è¯¥å®¢æ·ç«¯ç HandleClientAsync å¯å¨æ å¿ |
| | | _handleClientStarted.TryRemove(clientId, out _); |
| | | |
| | | // é置该客æ·ç«¯çç¶æä¿¡æ¯ |
| | | _stateManager.TryUpdateStateSafely(clientId, state => |
| | | { |
| | | state.IsEventSubscribed = false; |
| | | state.CurrentAction = ""; |
| | | state.OperStatus = ""; |
| | | state.RobotArmObject = 0; |
| | | state.RobotControlMode = 0; |
| | | state.RobotRunMode = 0; |
| | | state.IsEventSubscribed = false; // åæ¶è®¢é
æ å¿ |
| | | state.CurrentAction = ""; // æ¸
é¤å½åå¨ä½ |
| | | state.OperStatus = ""; // æ¸
é¤è¿è¡ç¶æ |
| | | state.RobotArmObject = 0; // éç½®æèå¯¹è±¡ç¶æ |
| | | state.RobotControlMode = 0; // éç½®æ§å¶æ¨¡å¼ |
| | | state.RobotRunMode = 0; // éç½®è¿è¡æ¨¡å¼ |
| | | return state; |
| | | }); |
| | | |
| | | // 触åæå¼è¿æ¥äºä»¶ |
| | | // 触å客æ·ç«¯æå¼è¿æ¥äºä»¶ï¼éç¥ä¸å±ï¼å¦ RobotJobï¼ |
| | | // 使ç¨ç©ºçç¶æå¯¹è±¡ä½ä¸ºåå¤ï¼å¦æè·åä¸å°ï¼ |
| | | OnClientDisconnected?.Invoke(this, _stateManager.GetState(clientId) ?? new RobotSocketState { IPAddress = clientId }); |
| | | |
| | | // è¿å nullï¼å ä¸ºè¿æ¯äºä»¶å¤çèéçæ£çæ¶æ¯è·¯ç± |
| | | return Task.FromResult<string?>(null); |
| | | } |
| | | |
| | | /// <summary> |
| | | /// æ£æ¥å®¢æ·ç«¯æ¯å¦å·²è¿æ¥ |
| | | /// </summary> |
| | | /// <param name="ipAddress">è®¾å¤ IP å°å</param> |
| | | /// <returns>å¦æå·²è¿æ¥åè¿å true</returns> |
| | | public bool IsClientConnected(string ipAddress) |
| | | { |
| | | // è·åææå·²è¿æ¥å®¢æ·ç«¯ç ID å表 |
| | | var clientIds = _tcpSocket.GetClientIds(); |
| | | // æ£æ¥åè¡¨ä¸æ¯å¦å
嫿å®ç IP å°å |
| | | return clientIds.Contains(ipAddress); |
| | | } |
| | | |
| | | /// <summary> |
| | | /// åéæ¶æ¯å°å®¢æ·ç«¯ |
| | | /// </summary> |
| | | /// <remarks> |
| | | /// å°è£
TcpSocketServer çåéæ¹æ³ï¼æä¾æ´ç®æ´çæ¥å£ç»ä¸å¡å± |
| | | /// </remarks> |
| | | /// <param name="ipAddress">ç®æ 客æ·ç«¯ IP å°å</param> |
| | | /// <param name="message">è¦åéçæ¶æ¯å
容</param> |
| | | /// <returns>å鿝妿å</returns> |
| | | public async Task<bool> SendToClientAsync(string ipAddress, string message) |
| | | { |
| | | return await _tcpSocket.SendToClientAsync(ipAddress, message); |
| | | } |
| | | |
| | | /// <summary> |
| | | /// è·åTcpSocketServerå¼ç¨ï¼ç¨äºRobotJobç´æ¥è®¿é®ï¼ |
| | | /// è·å TcpSocketServer å¼ç¨ |
| | | /// </summary> |
| | | /// <remarks> |
| | | /// RobotJob å¯è½éè¦ç´æ¥è®¿é® TcpSocketServer è¿è¡é
ç½® |
| | | /// æ¤å±æ§æä¾åªè¯»è®¿é® |
| | | /// </remarks> |
| | | public TcpSocketServer TcpSocket => _tcpSocket; |
| | | } |
| | | } |
| | |
| | | using Quartz; |
| | | using Microsoft.Extensions.Logging; |
| | | using Quartz; |
| | | using System.Net; |
| | | using WIDESEA_Core; |
| | | using WIDESEAWCS_Core.Caches; |
| | | using WIDESEAWCS_Core.Helper; |
| | | using WIDESEAWCS_Core.LogHelper; |
| | | using WIDESEAWCS_ITaskInfoService; |
| | | using WIDESEAWCS_QuartzJob; |
| | | using WIDESEAWCS_Tasks.Workflow.Abstractions; |
| | | using WIDESEAWCS_Tasks.Workflow; |
| | | using WIDESEAWCS_Tasks.SocketServer; |
| | | using Microsoft.Extensions.Logging; |
| | | using WIDESEAWCS_Tasks.Workflow; |
| | | using WIDESEAWCS_Tasks.Workflow.Abstractions; |
| | | |
| | | namespace WIDESEAWCS_Tasks |
| | | { |
| | | /// <summary> |
| | | /// æºå¨äººä»»å¡ä½ä¸ï¼è´è´£è°åº¦ä¸çå½å¨æç®¡çï¼å
·ä½ç¶ææºæµç¨äº¤ç»ç¼æå¨ã |
| | | /// æºå¨äººä»»å¡ä½ä¸ï¼Quartz Jobï¼- è´è´£è°åº¦ä¸çå½å¨æç®¡ç |
| | | /// </summary> |
| | | /// <remarks> |
| | | /// Quartz 宿¶ä»»å¡ï¼æ¯ç§æ§è¡ä¸æ¬¡ï¼é»è®¤ï¼ï¼ä¸»è¦èè´£ï¼ |
| | | /// 1. ä» JobDataMap è·å设å¤ä¿¡æ¯ |
| | | /// 2. ç¡®ä¿ TCP 客æ·ç«¯å·²è¿æ¥å¹¶è®¢é
æ¶æ¯ |
| | | /// 3. 轮询å¾
å¤ççæºå¨äººä»»å¡ |
| | | /// 4. è°ç¨å·¥ä½æµç¼æå¨æ§è¡ä»»å¡ç¶ææº |
| | | /// |
| | | /// ä½¿ç¨ [DisallowConcurrentExecution] ç¦æ¢å¹¶åæ§è¡ï¼ç¡®ä¿åä¸è®¾å¤çä»»å¡ä¸²è¡å¤çã |
| | | /// å
·ä½çç¶ææºæµç¨é»è¾å§æç» <see cref="RobotWorkflowOrchestrator"/> å¤çã |
| | | /// </remarks> |
| | | [DisallowConcurrentExecution] |
| | | public class RobotJob : IJob |
| | | { |
| | | /// <summary> |
| | | /// 任塿»æ°ä¸é |
| | | /// </summary> |
| | | /// <remarks> |
| | | /// 彿ºå¨äººå¤ççè´§ç©æ°éè¾¾å°æ¤ä¸éæ¶ï¼ä¸åä¸åæ°ä»»å¡ã |
| | | /// 鲿¢æºå¨äººè¿åº¦å³ç´¯æç³»ç»è¿è½½ã |
| | | /// </remarks> |
| | | private const int MaxTaskTotalNum = 48; |
| | | |
| | | /// <summary> |
| | | /// æ¶æ¯äºä»¶è®¢é
æ å¿ |
| | | /// </summary> |
| | | /// <remarks> |
| | | /// 使ç¨ååæä½ç¡®ä¿å
¨å±åªè®¢é
䏿¬¡ TCP æ¶æ¯äºä»¶ã |
| | | /// 鲿¢å¤ä¸ª Job å®ä¾éå¤è®¢é
å¯¼è´æ¶æ¯è¢«å¤æ¬¡å¤çã |
| | | /// </remarks> |
| | | private static int _messageSubscribedFlag; |
| | | |
| | | /// <summary> |
| | | /// æºæ¢°æå®¢æ·ç«¯è¿æ¥ç®¡çå¨ |
| | | /// </summary> |
| | | /// <remarks> |
| | | /// è´è´£ç®¡ç TCP è¿æ¥ççå½å¨æï¼å
æ¬è¿æ¥ãæå¼ãæ¶æ¯åéçã |
| | | /// </remarks> |
| | | private readonly RobotClientManager _clientManager; |
| | | |
| | | /// <summary> |
| | | /// æºæ¢°æç¶æç®¡çå¨ |
| | | /// </summary> |
| | | /// <remarks> |
| | | /// è´è´£ç®¡ç Redis ç¼åä¸çæºæ¢°æç¶æï¼å
æ¬è¯»ååå¹¶åæ§å¶ã |
| | | /// </remarks> |
| | | private readonly RobotStateManager _stateManager; |
| | | |
| | | /// <summary> |
| | | /// æ¶æ¯è·¯ç±å¨ |
| | | /// </summary> |
| | | /// <remarks> |
| | | /// è´è´£å¤çä» TCP æå¡å¨æ¥æ¶å°çæ¶æ¯ï¼å¹¶ååç»åéçå¤çå¨ã |
| | | /// æ¯æ¶æ¯å¤ç管éçå
¥å£ã |
| | | /// </remarks> |
| | | private readonly IRobotMessageRouter _messageRouter; |
| | | |
| | | /// <summary> |
| | | /// æºå¨äººä»»å¡å¤çå¨ |
| | | /// </summary> |
| | | /// <remarks> |
| | | /// è´è´£ä»»å¡çä¸åãç¶ææ´æ°ãä¸ WMS ç交äºçã |
| | | /// </remarks> |
| | | private readonly RobotTaskProcessor _taskProcessor; |
| | | |
| | | /// <summary> |
| | | /// æºå¨äººå·¥ä½æµç¼æå¨ |
| | | /// </summary> |
| | | /// <remarks> |
| | | /// è´è´£æ§è¡ä»»å¡çç¶ææºæµè½¬ï¼æ ¹æ®å½åç¶æå³å®ä¸ä¸æ¥å¨ä½ã |
| | | /// è¿æ¯æ ¸å¿çä¸å¡é»è¾ç¼æç»ä»¶ã |
| | | /// </remarks> |
| | | private readonly IRobotWorkflowOrchestrator _workflowOrchestrator; |
| | | |
| | | /// <summary> |
| | | /// æ¥å¿è®°å½å¨ |
| | | /// </summary> |
| | | private readonly ILogger<RobotJob> _logger; |
| | | |
| | | /// <summary> |
| | | /// æé 彿° |
| | | /// </summary> |
| | | /// <remarks> |
| | | /// éç¨ä¾èµæ³¨å
¥æ¹å¼è·åæéæå¡ï¼å¹¶å®æç»ä»¶çåå§ååç»è£
ã |
| | | /// è¿éä½ç°äº"æ§å¶å转"å"ä¾èµæ³¨å
¥"ç设计ååã |
| | | /// </remarks> |
| | | /// <param name="tcpSocket">TCP Socket æå¡å¨å®ä¾</param> |
| | | /// <param name="robotTaskService">æºå¨äººä»»å¡æå¡</param> |
| | | /// <param name="taskService">éç¨ä»»å¡æå¡</param> |
| | | /// <param name="cache">ç¼åæå¡</param> |
| | | /// <param name="httpClientHelper">HTTP 客æ·ç«¯å¸®å©ç±»ï¼ç¨äºè°ç¨ WMS æ¥å£</param> |
| | | /// <param name="logger">æ¥å¿è®°å½å¨</param> |
| | | public RobotJob( |
| | | TcpSocketServer tcpSocket, |
| | | IRobotTaskService robotTaskService, |
| | |
| | | HttpClientHelper httpClientHelper, |
| | | ILogger<RobotJob> logger) |
| | | { |
| | | // åå§åç¶æç®¡çå¨ï¼ä¼ å
¥ç¼åæå¡ |
| | | _stateManager = new RobotStateManager(cache); |
| | | _logger = logger; |
| | | |
| | | // æ¶å£ Socket 访é®ï¼åç»è¥æ¿æ¢éä¿¡å®ç°åªéæ¿æ¢ç½å
³å±ã |
| | | // å建 Socket ç½å
³ï¼å°è£
TcpSocketServer çè®¿é® |
| | | // åç»æ¿æ¢éä¿¡å®ç°æ¶åªéæ¿æ¢ç½å
³å± |
| | | ISocketClientGateway socketGateway = new SocketClientGateway(tcpSocket); |
| | | |
| | | // åå§åä»»å¡å¤çå¨ |
| | | _taskProcessor = new RobotTaskProcessor(socketGateway, _stateManager, robotTaskService, taskService, httpClientHelper); |
| | | |
| | | // åå§å客æ·ç«¯ç®¡çå¨ |
| | | _clientManager = new RobotClientManager(tcpSocket, _stateManager); |
| | | |
| | | // åå§åå½ä»¤å¤çå¨ |
| | | // ç®åå½ä»¤å¤çå¨ï¼å¤çç¶ææ´æ°çç®åå½ä»¤ |
| | | var simpleCommandHandler = new RobotSimpleCommandHandler(_taskProcessor); |
| | | // åç¼å½ä»¤å¤çå¨ï¼å¤ç pickfinishedãputfinished ç另忰çå½ä»¤ |
| | | var prefixCommandHandler = new RobotPrefixCommandHandler(robotTaskService, _taskProcessor, _stateManager, socketGateway); |
| | | |
| | | // åå§åæ¶æ¯è·¯ç±å¨ |
| | | _messageRouter = new RobotMessageHandler(socketGateway, _stateManager, cache, simpleCommandHandler, prefixCommandHandler, logger); |
| | | |
| | | // åå§å工使µç¼æå¨ |
| | | _workflowOrchestrator = new RobotWorkflowOrchestrator(_stateManager, _clientManager, _taskProcessor, robotTaskService); |
| | | |
| | | // 订é
客æ·ç«¯æå¼è¿æ¥äºä»¶ |
| | | _clientManager.OnClientDisconnected += OnClientDisconnected; |
| | | |
| | | // å
¨å±åªè®¢é
䏿¬¡æ¶æ¯äºä»¶ï¼ä¿æåæè¡ä¸ºã |
| | | // å
¨å±åªè®¢é
䏿¬¡ TCP æ¶æ¯äºä»¶ï¼ä¿æåæè¡ä¸ºï¼ |
| | | // ä½¿ç¨ Interlocked.CompareExchange å®ç°ååæä½ |
| | | if (System.Threading.Interlocked.CompareExchange(ref _messageSubscribedFlag, 1, 0) == 0) |
| | | { |
| | | // å°æ¶æ¯è·¯ç±å¨çå¤çæ¹æ³ç»å®å° TCP æå¡å¨çæ¶æ¯æ¥æ¶äºä»¶ |
| | | tcpSocket.MessageReceived += _messageRouter.HandleMessageReceivedAsync; |
| | | Console.WriteLine($"[{DateTime.Now:yyyy-MM-dd HH:mm:ss}] æºå¨æTCPæ¶æ¯äºä»¶å·²è®¢é
"); |
| | | _logger.LogError("æºå¨æTCPæ¶æ¯äºä»¶å·²è®¢é
"); |
| | | QuartzLogger.Error($"æºå¨æTCPæ¶æ¯äºä»¶å·²è®¢é
"); |
| | | } |
| | | } |
| | | |
| | | /// <summary> |
| | | /// 客æ·ç«¯æå¼è¿æ¥çäºä»¶å¤ç |
| | | /// </summary> |
| | | /// <remarks> |
| | | /// å½å®¢æ·ç«¯æå¼è¿æ¥æ¶è®°å½æ¥å¿ï¼ä¾¿äºææ¥é®é¢ã |
| | | /// </remarks> |
| | | /// <param name="sender">äºä»¶åéè
</param> |
| | | /// <param name="state">æå¼è¿æ¥çæºæ¢°æç¶æ</param> |
| | | private void OnClientDisconnected(object? sender, RobotSocketState state) |
| | | { |
| | | Console.WriteLine($"[{DateTime.Now:yyyy-MM-dd HH:mm:ss}] 客æ·ç«¯å·²æå¼è¿æ¥: {state.IPAddress}"); |
| | | _logger.LogError("客æ·ç«¯å·²æå¼è¿æ¥"); |
| | | QuartzLogger.Error($"客æ·ç«¯å·²æå¼è¿æ¥", state.RobotCrane.DeviceName); |
| | | } |
| | | |
| | | /// <summary> |
| | | /// Quartz Job çæ§è¡å
¥å£ |
| | | /// </summary> |
| | | /// <remarks> |
| | | /// æ§è¡æµç¨ï¼ |
| | | /// 1. ä» JobDataMap è·å设å¤ä¿¡æ¯ |
| | | /// 2. ç¡®ä¿å®¢æ·ç«¯å·²è¿æ¥å¹¶è®¢é
æ¶æ¯ |
| | | /// 3. 轮询å¾
å¤çä»»å¡ |
| | | /// 4. è°ç¨å·¥ä½æµç¼æå¨æ§è¡ä»»å¡ |
| | | /// |
| | | /// 注æï¼æ¤æ¹æ³å¯è½é¢ç¹è°ç¨ï¼æ¯ç§ä¸æ¬¡ï¼ï¼éæ³¨ææ§è½ã |
| | | /// </remarks> |
| | | /// <param name="context">Quartz ä½ä¸æ§è¡ä¸ä¸æï¼å
å«ä½ä¸è¯¦æ
åæ°æ®</param> |
| | | public async Task Execute(IJobExecutionContext context) |
| | | { |
| | | // ä» JobDataMap ä¸è·åä½ä¸åæ° |
| | | bool flag = context.JobDetail.JobDataMap.TryGetValue("JobParams", out object? value); |
| | | |
| | | // å°åæ°è½¬æ¢ä¸ºæºå¨äººè®¾å¤ä¿¡æ¯ |
| | | RobotCraneDevice robotCrane = (RobotCraneDevice?)value ?? new RobotCraneDevice(); |
| | | |
| | | // å¦ææ²¡æè·åå°ææç设å¤ä¿¡æ¯ï¼ç´æ¥è¿å |
| | | if (!flag || robotCrane.IsNullOrEmpty()) |
| | | { |
| | | return; |
| | | } |
| | | |
| | | // è·åè®¾å¤ IP å°åï¼ä½ä¸ºç¶æç¼åçé® |
| | | string ipAddress = robotCrane.IPAddress; |
| | | |
| | | // è·åæå建设å¤ç¶æå¯¹è±¡ |
| | | RobotSocketState state = _stateManager.GetOrCreateState(ipAddress, robotCrane); |
| | | |
| | | // æ´æ°è®¾å¤åºç¡ä¿¡æ¯ï¼ä»¥é²è®¾å¤ä¿¡æ¯å¨è¿è¡æé´åçååï¼ |
| | | state.RobotCrane = robotCrane; |
| | | |
| | | try |
| | | { |
| | | // ç¡®ä¿å®¢æ·ç«¯å·²è¿æ¥å¹¶è®¢é
æ¶æ¯äºä»¶ |
| | | // 妿客æ·ç«¯æªè¿æ¥æè®¢é
失败ï¼ç´æ¥è¿åçå¾
䏿¬¡è°åº¦ |
| | | if (!_clientManager.EnsureClientSubscribed(ipAddress, robotCrane)) |
| | | { |
| | | return; |
| | | } |
| | | |
| | | // 轮询è·å该设å¤çå¾
å¤çä»»å¡ |
| | | var task = _taskProcessor.GetTask(robotCrane); |
| | | |
| | | // 妿æå¾
å¤çä»»å¡ |
| | | if (task != null) |
| | | { |
| | | // è·åææ°ç设å¤ç¶æ |
| | | var latestState = _stateManager.GetState(ipAddress); |
| | | if (latestState == null) |
| | | { |
| | | // ç¶æä¸åå¨ï¼å¯è½è®¾å¤æªåå§å |
| | | return; |
| | | } |
| | | |
| | | // æ£æ¥ä»»å¡æ»æ°æ¯å¦æªè¾¾å°ä¸é |
| | | if (latestState.RobotTaskTotalNum < MaxTaskTotalNum) |
| | | { |
| | | // è°ç¨å·¥ä½æµç¼æå¨æ§è¡ä»»å¡ |
| | | // ç¼æå¨ä¼æ ¹æ®å½åç¶æå³å®ä¸ä¸æ¥å¨ä½ |
| | | await _workflowOrchestrator.ExecuteAsync(latestState, task, ipAddress); |
| | | } |
| | | } |
| | | } |
| | | catch (Exception) |
| | | catch (Exception ex) |
| | | { |
| | | // å¼å¸¸å¤çå·²å¨ç»ä»¶å
é¨è¿è¡ï¼Job å±ä¿æå
åºååè¯ä¹ã |
| | | // å¼å¸¸å¤çå·²å¨ç»ä»¶å
é¨è¿è¡ï¼Job å±ä¿æå
åºè¯ä¹ |
| | | // è®°å½å¼å¸¸è䏿¯éé»åæï¼ä¾¿äºææ¥é®é¢ |
| | | _logger?.LogError(ex, "RobotJobæ§è¡å¼å¸¸ï¼IP: {IpAddress}", ipAddress); |
| | | QuartzLogger.Error($"RobotJobæ§è¡å¼å¸¸ï¼IP: {ipAddress}", state.RobotCrane.DeviceName, ex); |
| | | } |
| | | } |
| | | } |
| | |
| | | using Microsoft.Extensions.Logging; |
| | | using Microsoft.Extensions.Logging; |
| | | using System.Net; |
| | | using System.Net.Sockets; |
| | | using WIDESEAWCS_Common; |
| | | using WIDESEAWCS_Core.Caches; |
| | | using WIDESEAWCS_Core.LogHelper; |
| | | using WIDESEAWCS_Tasks.Workflow.Abstractions; |
| | | |
| | | namespace WIDESEAWCS_Tasks |
| | | { |
| | | /// <summary> |
| | | /// æºå¨äººæ¶æ¯è·¯ç±å
¥å£ï¼è´è´£ç¼åç¶æè¯»åãå½ä»¤ååååå
触åã |
| | | /// æºå¨äººæ¶æ¯å¤çå¨ - æ¶æ¯è·¯ç±å
¥å£ |
| | | /// </summary> |
| | | /// <remarks> |
| | | /// æ ¸å¿èè´£ï¼ |
| | | /// 1. ç¼åç¶æè¯»åï¼ä» Redis ä¸è·åæºå¨äººææ°çç¶æ |
| | | /// 2. å½ä»¤ååï¼æ ¹æ®æ¶æ¯ç±»åååç»ä¸åçå¤çå¨ |
| | | /// - ç®åå½ä»¤ï¼å¦ homingãrunningï¼ï¼ç± <see cref="IRobotSimpleCommandHandler"/> å¤ç |
| | | /// - åç¼å½ä»¤ï¼å¦ pickfinishedãputfinishedï¼ï¼ç± <see cref="IRobotPrefixCommandHandler"/> å¤ç |
| | | /// 3. åå
触åï¼å°åå§æ¶æ¯ååå°å®¢æ·ç«¯ |
| | | /// |
| | | /// è¿æ¯æ¶æ¯å¤ç管éçå
¥å£ç¹ï¼ç± TcpSocketServer ç MessageReceived äºä»¶è§¦åã |
| | | /// </remarks> |
| | | public class RobotMessageHandler : IRobotMessageRouter |
| | | { |
| | | /// <summary> |
| | | /// Socket 客æ·ç«¯ç½å
³æ¥å£ |
| | | /// </summary> |
| | | /// <remarks> |
| | | /// ç¨äºå客æ·ç«¯åéååºæ¶æ¯ã |
| | | /// </remarks> |
| | | private readonly ISocketClientGateway _socketClientGateway; |
| | | |
| | | /// <summary> |
| | | /// æºæ¢°æç¶æç®¡çå¨ |
| | | /// </summary> |
| | | /// <remarks> |
| | | /// ç¨äºè¯»ååæ´æ°æºå¨äººçç¶æã |
| | | /// </remarks> |
| | | private readonly RobotStateManager _stateManager; |
| | | |
| | | /// <summary> |
| | | /// ç¼åæå¡ |
| | | /// </summary> |
| | | /// <remarks> |
| | | /// ç´æ¥ä½¿ç¨ç¼åæå¡æ£æ¥ç¶ææ¯å¦åå¨ã |
| | | /// </remarks> |
| | | private readonly ICacheService _cache; |
| | | |
| | | /// <summary> |
| | | /// ç®åå½ä»¤å¤çå¨ |
| | | /// </summary> |
| | | /// <remarks> |
| | | /// å¤çç®åçç¶ææ´æ°å½ä»¤ï¼å¦è¿è¡ç¶æã模å¼åæ¢çã |
| | | /// </remarks> |
| | | private readonly IRobotSimpleCommandHandler _simpleCommandHandler; |
| | | |
| | | /// <summary> |
| | | /// åç¼å½ä»¤å¤çå¨ |
| | | /// </summary> |
| | | /// <remarks> |
| | | /// å¤ç另忰çåç¼å½ä»¤ï¼å¦ pickfinishedï¼åè´§å®æï¼ãputfinishedï¼æ¾è´§å®æï¼ã |
| | | /// </remarks> |
| | | private readonly IRobotPrefixCommandHandler _prefixCommandHandler; |
| | | |
| | | /// <summary> |
| | | /// æ¥å¿è®°å½å¨ |
| | | /// </summary> |
| | | private readonly ILogger<RobotJob> _logger; |
| | | |
| | | /// <summary> |
| | | /// æé 彿° |
| | | /// </summary> |
| | | /// <param name="socketClientGateway">Socket ç½å
³</param> |
| | | /// <param name="stateManager">ç¶æç®¡çå¨</param> |
| | | /// <param name="cache">ç¼åæå¡</param> |
| | | /// <param name="simpleCommandHandler">ç®åå½ä»¤å¤çå¨</param> |
| | | /// <param name="prefixCommandHandler">åç¼å½ä»¤å¤çå¨</param> |
| | | /// <param name="logger">æ¥å¿è®°å½å¨</param> |
| | | public RobotMessageHandler( |
| | | ISocketClientGateway socketClientGateway, |
| | | RobotStateManager stateManager, |
| | |
| | | } |
| | | |
| | | /// <summary> |
| | | /// å¤çæ¥æ¶å°çæ¶æ¯ãä¿æåæè¡ä¸ºï¼ç®åå½ä»¤ååç¼å½ä»¤é½åååæ¶æ¯ã |
| | | /// å¤çæ¥æ¶å°çæ¶æ¯ |
| | | /// </summary> |
| | | /// <remarks> |
| | | /// å¤çæµç¨ï¼ |
| | | /// 1. è®°å½æ¥å¿ï¼è®°å½åå§æ¶æ¯å
å®¹ï¼ |
| | | /// 2. éªè¯ç¼å䏿¯å¦åå¨è¯¥è®¾å¤çç¶æ |
| | | /// 3. å°è¯ç¨ç®åå½ä»¤å¤çå¨å¤çï¼ç¶ææ´æ°ç±»å½ä»¤ï¼ |
| | | /// - 妿å¤çæåï¼åååæ¶æ¯å¹¶æ´æ°ç¶æ |
| | | /// 4. 妿䏿¯ç®åå½ä»¤ï¼æ£æ¥æ¯å¦æ¯åç¼å½ä»¤ï¼pickfinished/putfinishedï¼ |
| | | /// - 妿æ¯ï¼è°ç¨åç¼å½ä»¤å¤çå¨å¤ç |
| | | /// 5. ä¿æåæè¡ä¸ºï¼ç®åå½ä»¤ååç¼å½ä»¤é½åååæ¶æ¯ |
| | | /// |
| | | /// 注æï¼æ¤æ¹æ³å¯è½å¨ TCP æ¶æ¯æ¥æ¶çä¸ä¸æä¸è¢«é¢ç¹è°ç¨ï¼éæ³¨ææ§è½ã |
| | | /// </remarks> |
| | | /// <param name="message">åå§æ¶æ¯å符串</param> |
| | | /// <param name="isJson">æ¶æ¯æ¯å¦ä¸º JSON æ ¼å¼ï¼å½åæªä½¿ç¨ï¼</param> |
| | | /// <param name="client">TCP 客æ·ç«¯è¿æ¥</param> |
| | | /// <param name="state">æºå¨äººå½åç¶æ</param> |
| | | /// <returns>ååºæ¶æ¯ï¼å¦ææ éåå¤åè¿å null</returns> |
| | | public async Task<string?> HandleMessageReceivedAsync(string message, bool isJson, TcpClient client, RobotSocketState state) |
| | | { |
| | | // è®°å½æ¥æ¶å°çæ¶æ¯æ¥å¿ |
| | | _logger.LogInformation($"æ¥æ¶å°å®¢æ·ç«¯ã{state.RobotCrane.DeviceName}ãåéæ¶æ¯ã{message}ã"); |
| | | QuartzLogger.Error($"æ¥æ¶å°å®¢æ·ç«¯æ¶æ¯ã{message}ã", state.RobotCrane.DeviceName); |
| | | |
| | | // æå»ºç¼åé®ï¼æ£æ¥ Redis 䏿¯å¦åå¨è¯¥è®¾å¤çç¶æ |
| | | var cacheKey = $"{RedisPrefix.Code}:{RedisName.SocketDevices}:{client.Client.RemoteEndPoint}"; |
| | | |
| | | // 妿ç¼åä¸ä¸åå¨æç¶æä¸º nullï¼å¿½ç¥æ¤æ¶æ¯ |
| | | if (!_cache.TryGetValue(cacheKey, out RobotSocketState? cachedState) || cachedState == null) |
| | | { |
| | | return null; |
| | | } |
| | | |
| | | // 使ç¨ç¼åä¸è·åçç¶æ |
| | | var activeState = cachedState; |
| | | |
| | | // å°æ¶æ¯è½¬æ¢ä¸ºå°åï¼ç¨äºç®åå½ä»¤å¹é
ï¼ |
| | | string messageLower = message.ToLowerInvariant(); |
| | | |
| | | // å°è¯ç¨ç®åå½ä»¤å¤çå¨å¤ç |
| | | // ç®åå½ä»¤å
æ¬ï¼homingãhomedãrunningãpausingãrunmodeãcontrolmode ç |
| | | if (await _simpleCommandHandler.HandleAsync(messageLower, activeState)) |
| | | { |
| | | // å¤çæååï¼å°åæ¶æ¯ååå°å®¢æ·ç«¯ï¼ä¿æåæè¡ä¸ºï¼ |
| | | await _socketClientGateway.SendMessageAsync(client, message); |
| | | _logger.LogInformation($"åéæ¶æ¯ã{message}ã"); |
| | | QuartzLogger.Error($"åéæ¶æ¯ï¼ã{message}ã", state.RobotCrane.DeviceName); |
| | | |
| | | // å®å
¨æ´æ°ç¶æå° Redis |
| | | _stateManager.TryUpdateStateSafely(activeState.IPAddress, activeState); |
| | | return null; |
| | | } |
| | | |
| | | // 妿䏿¯ç®åå½ä»¤ï¼æ£æ¥æ¯å¦æ¯åç¼å½ä»¤ |
| | | // åç¼å½ä»¤å
æ¬ï¼pickfinishedãputfinishedï¼åé¢è·éå·åéçä½ç½®åæ°ï¼ |
| | | if (_prefixCommandHandler.IsPrefixCommand(messageLower)) |
| | | { |
| | | // è°ç¨åç¼å½ä»¤å¤çå¨ |
| | | // åç¼å½ä»¤å¤çå¨ä¼è§£æä½ç½®åæ°å¹¶æ´æ°ç¶æ |
| | | await _prefixCommandHandler.HandleAsync(message, activeState, client); |
| | | } |
| | | |
| | | // é»è®¤è¿å nullï¼ä¸äº§çååºæ¶æ¯ |
| | | return null; |
| | | } |
| | | } |
| | |
| | | namespace WIDESEAWCS_Tasks |
| | | { |
| | | /// <summary> |
| | | /// æºæ¢°æSocketéä¿¡ç¶æ |
| | | /// æºæ¢°æ Socket éä¿¡ç¶ææ°æ®ç±» |
| | | /// </summary> |
| | | /// <remarks> |
| | | /// 该类ç¨äºå¨ Redis ç¼åä¸å卿ºæ¢°æç宿¶ç¶æï¼å
æ¬ä½ç½®ãä»»å¡ãæè对象çä¿¡æ¯ã |
| | | /// ææå±æ§å设计为线ç¨å®å
¨æ´æ°ï¼éè¿ <see cref="RobotStateManager"/> ççæ¬æ§å¶æºå¶æ¥é²æ¢å¹¶åè¦çã |
| | | /// </remarks> |
| | | public class RobotSocketState |
| | | { |
| | | /// <summary> |
| | | /// æºæ¢°æç IP å°åï¼ä½ä¸ºç¼åé®çå¯ä¸æ è¯ |
| | | /// </summary> |
| | | public string IPAddress { get; set; } = string.Empty; |
| | | |
| | | /// <summary> |
| | | /// çæ¬å·ï¼ç¨äºé²æ¢å¹¶åæ´æ°æ¶æ§å¼è¦çæ°å¼ |
| | | /// æ¯æ¬¡ä¿®æ¹ç¶ææ¶é½åºè¯¥æ´æ°æ¤å¼ |
| | | /// çæ¬å·ï¼ç¨äºä¹è§å¹¶åæ§å¶ |
| | | /// </summary> |
| | | /// <remarks> |
| | | /// æ¯æ¬¡ä¿®æ¹ç¶ææ¶æ´æ°ä¸º DateTime.UtcNow.Ticksã |
| | | /// <see cref="RobotStateManager"/> ä½¿ç¨æ¤å段å®ç°ä¹è§éï¼é²æ¢å¹¶åæ´æ°æ¶æ§å¼è¦çæ°å¼ã |
| | | /// </remarks> |
| | | public long Version { get; set; } = DateTime.UtcNow.Ticks; |
| | | |
| | | /// <summary> |
| | | /// æ¯å¦å·²è®¢é
æ¶æ¯äºä»¶ |
| | | /// æ¯å¦å·²è®¢é
æ¶æ¯äºä»¶æ å¿ |
| | | /// </summary> |
| | | /// <remarks> |
| | | /// ç¡®ä¿æ¯ä¸ªå®¢æ·ç«¯åªå¯å¨ä¸æ¬¡æ¶æ¯å¤ç循ç¯ï¼é¿å
éå¤è®¢é
导è´çæ¶æ¯éå¤å¤çã |
| | | /// </remarks> |
| | | public bool IsEventSubscribed { get; set; } |
| | | |
| | | /// <summary> |
| | | /// æºæ¢°æè¿è¡æ¨¡å¼ |
| | | /// </summary> |
| | | /// <remarks> |
| | | /// 1: æå¨æ¨¡å¼ |
| | | /// 2: èªå¨æ¨¡å¼ |
| | | /// å½ RobotRunMode == 2 ä¸ RobotControlMode == 1 æ¶ï¼ç³»ç»è¿å
¥èªå¨æ§å¶ç¶æã |
| | | /// </remarks> |
| | | public int? RobotRunMode { get; set; } |
| | | |
| | | /// <summary> |
| | | /// æºæ¢°ææ§å¶æ¨¡å¼ |
| | | /// </summary> |
| | | /// <remarks> |
| | | /// 1: 客æ·ç«¯æ§å¶ |
| | | /// 2: æªç¥/å
¶ä» |
| | | /// ä¸ RobotRunMode é
å夿æºå¨äººçå½åæ§å¶ç¶æã |
| | | /// </remarks> |
| | | public int? RobotControlMode { get; set; } |
| | | |
| | | /// <summary> |
| | | /// æºæ¢°ææ¯å¦æåç©æï¼0-æ ç©æï¼1-æç©æ |
| | | /// æºæ¢°ææèæåå¯¹è±¡ç¶æ |
| | | /// </summary> |
| | | /// <remarks> |
| | | /// 0: æ ç©æï¼æè空é²ï¼ |
| | | /// 1: æç©æï¼å·²æåè´§ç©ï¼ |
| | | /// ç¨äºå¤ææºå¨äººæ¯å¦å¯ä»¥æ§è¡ä¸ä¸æ¥å¨ä½ã |
| | | /// </remarks> |
| | | public int? RobotArmObject { get; set; } |
| | | |
| | | /// <summary> |
| | | /// æºæ¢°æè®¾å¤ä¿¡æ¯ |
| | | /// æºæ¢°æè®¾å¤åºç¡ä¿¡æ¯ |
| | | /// </summary> |
| | | /// <remarks> |
| | | /// å
å«è®¾å¤ç DeviceCodeãDeviceNameãIPAddress çåºç¡ä¿¡æ¯ã |
| | | /// å¨ç¶æåå§åæ¶ä» JobDetail.JobDataMap è·åå¹¶ç¼åã |
| | | /// </remarks> |
| | | public RobotCraneDevice? RobotCrane { get; set; } |
| | | |
| | | /// <summary> |
| | | /// å½åå¨ä½ |
| | | /// æºæ¢°æå½åæ£å¨æ§è¡çå¨ä½ |
| | | /// </summary> |
| | | /// <remarks> |
| | | /// å¯è½çå¼ï¼ |
| | | /// - "Picking": åè´§ä¸ |
| | | /// - "Putting": æ¾è´§ä¸ |
| | | /// - "PickFinished": åè´§å®æ |
| | | /// - "PutFinished": æ¾è´§å®æ |
| | | /// - "AllPickFinished": å
¨é¨åè´§å®æ |
| | | /// - "AllPutFinished": å
¨é¨æ¾è´§å®æ |
| | | /// </remarks> |
| | | public string? CurrentAction { get; set; } |
| | | |
| | | /// <summary> |
| | | /// å½åç¶æ |
| | | /// æºæ¢°æå½åè¿è¡ç¶æ |
| | | /// </summary> |
| | | /// <remarks> |
| | | /// å¯è½çå¼ï¼ |
| | | /// - "Homing": åé¶ä¸ |
| | | /// - "Homed": å·²åé¶ |
| | | /// - "Running": è¿è¡ä¸ |
| | | /// - "Pausing": æåä¸ |
| | | /// - "Warming": é¢çä¸ |
| | | /// - "Emstoping": æ¥åä¸ |
| | | /// </remarks> |
| | | public string? OperStatus { get; set; } |
| | | |
| | | /// <summary> |
| | | /// åè´§å®æä½ç½® |
| | | /// æè¿ä¸æ¬¡åè´§å®æçä½ç½®æ°ç» |
| | | /// </summary> |
| | | /// <remarks> |
| | | /// æ°ç»ä¸çæ¯ä¸ªå
ç´ ä»£è¡¨ä¸ä¸ªçµæ± ä½ç½®ç¼å·ã |
| | | /// ç¨äºè®°å½åè´§å¨ä½æ¶åçè´§ä½ï¼ä¾åç»ç»ç/æçæä½ä½¿ç¨ã |
| | | /// </remarks> |
| | | public int[]? LastPickPositions { get; set; } |
| | | |
| | | /// <summary> |
| | | /// æ¾è´§å®æä½ç½® |
| | | /// æè¿ä¸æ¬¡æ¾è´§å®æçä½ç½®æ°ç» |
| | | /// </summary> |
| | | /// <remarks> |
| | | /// æ°ç»ä¸çæ¯ä¸ªå
ç´ ä»£è¡¨ä¸ä¸ªçµæ± ä½ç½®ç¼å·ã |
| | | /// ç¨äºè®°å½æ¾è´§å¨ä½æ¶åçè´§ä½ã |
| | | /// </remarks> |
| | | public int[]? LastPutPositions { get; set; } |
| | | |
| | | /// <summary> |
| | | /// æåä½ç½®æ¡ç |
| | | /// çµæ± /è´§ä½æ¡ç å表 |
| | | /// </summary> |
| | | /// <remarks> |
| | | /// å¨ç»çæä½æ¶ç¨äºè®°å½çæçæçæ¡ç ã |
| | | /// æ¯ä¸ªæ¡ç æ ¼å¼ä¸º "TRAY" + æ¥æ + æ¶é´ + éæºæ°ã |
| | | /// </remarks> |
| | | public List<string> CellBarcode { get; set; } = new List<string>(); |
| | | |
| | | /// <summary> |
| | | /// å½åæåä»»å¡ |
| | | /// æºæ¢°æå½åæ£å¨æ§è¡çä»»å¡ |
| | | /// </summary> |
| | | /// <remarks> |
| | | /// å½ä»»å¡ä¸åå°æºå¨äººåï¼è¯¥å段ä¿åä»»å¡è¯¦æ
ã |
| | | /// ä»»å¡ç±»åå
æ¬ï¼ç»ç(500)ãæ¢ç(510)ãæç(520)ã |
| | | /// </remarks> |
| | | public Dt_RobotTask? CurrentTask { get; set; } |
| | | |
| | | /// <summary> |
| | | /// æ¯å¦éè¦æç |
| | | /// æ¯å¦éè¦æ§è¡æçä»»å¡ |
| | | /// </summary> |
| | | /// <remarks> |
| | | /// å½ä»»å¡ç±»å为 SplitPallet (520) æ¶è®¾ä¸º trueã |
| | | /// æçä»»å¡å°çµæ± 仿çä¸åä¸å¹¶é个æ¾ç½®å°ç®æ ä½ç½®ã |
| | | /// </remarks> |
| | | public bool IsSplitPallet { get; set; } |
| | | |
| | | /// <summary> |
| | | /// æ¯å¦éè¦ç»ç |
| | | /// æ¯å¦éè¦æ§è¡ç»çä»»å¡ |
| | | /// </summary> |
| | | /// <remarks> |
| | | /// å½ä»»å¡ç±»å为 GroupPallet (500) æ ChangePallet (510) æ¶è®¾ä¸º trueã |
| | | /// ç»çä»»å¡å°å¤ä¸ªçµæ± ç»åå°åä¸ä¸ªæçä¸ã |
| | | /// </remarks> |
| | | public bool IsGroupPallet { get; set; } |
| | | |
| | | /// <summary> |
| | | /// 任塿»æ° |
| | | /// æºå¨äººå·²å¤çç任塿»æ° |
| | | /// </summary> |
| | | /// <remarks> |
| | | /// ç´¯è®¡è®°å½æºå¨äººå·²å®æå¤çççµæ± /è´§ç©æ°éã |
| | | /// å½è¾¾å° MaxTaskTotalNum (48) æ¶ï¼ä¸åä¸åæ°ä»»å¡ã |
| | | /// </remarks> |
| | | public int RobotTaskTotalNum { get; set; } |
| | | } |
| | | } |
| | |
| | | namespace WIDESEAWCS_Tasks |
| | | { |
| | | /// <summary> |
| | | /// æºæ¢°æç¶æç®¡çå¨ - è´è´£RobotSocketStateçå®å
¨æ´æ°åå
é |
| | | /// æºæ¢°æç¶æç®¡çå¨ - è´è´£ RobotSocketState ç线ç¨å®å
¨æ´æ°åå
é |
| | | /// </summary> |
| | | /// <remarks> |
| | | /// æ ¸å¿åè½æ¯éè¿ç¼åæå¡ï¼ICacheServiceï¼ç®¡ç Redis ä¸çæºæ¢°æç¶æã |
| | | /// æä¾ä¹è§å¹¶åæ§å¶ï¼éè¿çæ¬å·ï¼Versionï¼åæ®µé²æ¢å¹¶åæ´æ°æ¶çæ°æ®è¦çé®é¢ã |
| | | /// </remarks> |
| | | public class RobotStateManager |
| | | { |
| | | /// <summary> |
| | | /// ç¼åæå¡å®ä¾ï¼ç¨äºè¯»å Redis ä¸çç¶ææ°æ® |
| | | /// </summary> |
| | | private readonly ICacheService _cache; |
| | | |
| | | /// <summary> |
| | | /// æé 彿° |
| | | /// </summary> |
| | | /// <param name="cache">ç¼åæå¡å®ä¾ï¼é常为 HybridCacheServiceï¼</param> |
| | | public RobotStateManager(ICacheService cache) |
| | | { |
| | | _cache = cache; |
| | | } |
| | | |
| | | /// <summary> |
| | | /// å®å
¨æ´æ°RobotSocketStateç¼åï¼é²æ¢å¹¶åè¦ç |
| | | /// å®å
¨æ´æ° RobotSocketState ç¼åï¼é²æ¢å¹¶åè¦ç |
| | | /// </summary> |
| | | /// <param name="ipAddress">设å¤IPå°å</param> |
| | | /// <param name="updateAction">æ´æ°ç¶æçå§æï¼ä¼ å
¥å½åç¶æï¼è¿åä¿®æ¹åçæ°ç¶æï¼</param> |
| | | /// <returns>æ¯å¦æ´æ°æå</returns> |
| | | /// <remarks> |
| | | /// 使ç¨ä¹è§å¹¶å模å¼ï¼å
读åå½åçæ¬å·ï¼æ§è¡æ´æ°æ¶æ£æ¥çæ¬æ¯å¦ä¸è´ã |
| | | /// å¦æçæ¬ä¸å¹é
ï¼è¯´ææå
¶ä»çº¿ç¨å·²æ´æ°ï¼ï¼åæ´æ°å¤±è´¥è¿å falseã |
| | | /// </remarks> |
| | | /// <param name="ipAddress">è®¾å¤ IP å°åï¼ç¨äºæå»ºç¼åé®</param> |
| | | /// <param name="updateAction">æ´æ°ç¶æç姿彿°ï¼ä¼ å
¥å½åç¶æå¯æ¬ï¼è¿åä¿®æ¹åçæ°ç¶æ</param> |
| | | /// <returns>æ¯å¦æ´æ°æåï¼false è¡¨ç¤ºçæ¬å²çªæç¶æä¸åå¨</returns> |
| | | public bool TryUpdateStateSafely(string ipAddress, Func<RobotSocketState, RobotSocketState> updateAction) |
| | | { |
| | | // æå»º Redis ç¼åé®ï¼æ ¼å¼ï¼{RedisPrefix.Code}:{RedisName.SocketDevices}:{ipAddress} |
| | | var cacheKey = GetCacheKey(ipAddress); |
| | | |
| | | // ä»ç¼åè·åå½ååå¨çç¶æ |
| | | var currentState = _cache.Get<RobotSocketState>(cacheKey); |
| | | |
| | | // 妿ç¼åä¸ä¸åå¨è¯¥è®¾å¤çç¶æï¼ç´æ¥è¿å falseï¼åºç± GetOrCreateState å
åå»ºï¼ |
| | | if (currentState == null) |
| | | { |
| | | return false; |
| | | } |
| | | |
| | | // 使ç¨å½ååå¨ççæ¬å·ä½ä¸ºææçæ¬ |
| | | // è®°å½å½ååå¨ççæ¬å·ï¼ä½ä¸ºæ´æ°æ¶çææçæ¬ |
| | | var expectedVersion = currentState.Version; |
| | | |
| | | // åå»ºç¶æå¯æ¬è¿è¡ä¿®æ¹ï¼é¿å
ä¿®æ¹å对象å¼ç¨ï¼ |
| | | // åå»ºç¶æçæ·±æ·è´å¯æ¬ï¼é¿å
ç´æ¥ä¿®æ¹å对象å¼ç¨ |
| | | // è¿æ ·å¯ä»¥ç¡®ä¿å¨å¤çº¿ç¨ç¯å¢ä¸ï¼æ¯ä¸ªçº¿ç¨æä½çæ¯ç¬ç«çç¶æå¯æ¬ |
| | | var stateCopy = CloneState(currentState); |
| | | |
| | | // æ§è¡è°ç¨è
æä¾çæ´æ°é»è¾ï¼ä¼ å
¥å¯æ¬ç¶æï¼è·åæ°çç¶æå¯¹è±¡ |
| | | var newState = updateAction(stateCopy); |
| | | |
| | | // å°æ°ç¶æççæ¬å·æ´æ°ä¸ºææ°çæ¶é´æ³ï¼è¡¨ç¤ºæ°æ®å·²æ´æ° |
| | | newState.Version = DateTime.UtcNow.Ticks; |
| | | |
| | | // è°ç¨ç¼åæå¡çå®å
¨æ´æ°æ¹æ³ï¼ä¼ å
¥ææçæ¬åçæ¬æåå¨ |
| | | // 妿å½åçæ¬ä¸ææçæ¬ä¸ä¸è´ï¼å·²è¢«å
¶ä»çº¿ç¨æ´æ°ï¼ï¼åæ´æ°å¤±è´¥ |
| | | return _cache.TrySafeUpdate( |
| | | cacheKey, |
| | | newState, |
| | | expectedVersion, |
| | | s => s.Version |
| | | s => s.Version // æå®åªä¸ªå段ä½ä¸ºçæ¬å· |
| | | ); |
| | | } |
| | | |
| | | /// <summary> |
| | | /// å®å
¨æ´æ°RobotSocketStateç¼åï¼ç®åçæ¬ï¼ |
| | | /// å®å
¨æ´æ° RobotSocketState ç¼åçéè½½çæ¬ï¼ç´æ¥ä¼ å
¥æ°ç¶æï¼ |
| | | /// </summary> |
| | | /// <param name="ipAddress">设å¤IPå°å</param> |
| | | /// <param name="newState">æ°ç¶æï¼ä¼è¢«æ´æ°Versionåæ®µï¼</param> |
| | | /// <returns>æ¯å¦æ´æ°æå</returns> |
| | | /// <remarks> |
| | | /// ä¸ä¸ä¸ä¸ªéè½½çåºå«ï¼æ¤æ¹æ³ç´æ¥æ¥æ¶å®æ´çæ°ç¶æå¯¹è±¡ï¼è䏿¯æ´æ°å§æã |
| | | /// å¦æè®¾å¤ç¶æä¸åå¨äºç¼åä¸ï¼åç´æ¥æ·»å æ°ç¶æã |
| | | /// </remarks> |
| | | /// <param name="ipAddress">è®¾å¤ IP å°åï¼ç¨äºæå»ºç¼åé®</param> |
| | | /// <param name="newState">æ°ç¶æå¯¹è±¡ï¼æ¹æ³å
é¨ä¼æ´æ°å
¶ Version åæ®µï¼</param> |
| | | /// <returns>æ¯å¦æ´æ°æåï¼æ°å»ºè®¾ç½®ä¸º true</returns> |
| | | public bool TryUpdateStateSafely(string ipAddress, RobotSocketState newState) |
| | | { |
| | | // æå»º Redis ç¼åé® |
| | | var cacheKey = GetCacheKey(ipAddress); |
| | | |
| | | // ä»ç¼åè·åå½ååå¨çç¶æ |
| | | var currentState = _cache.Get<RobotSocketState>(cacheKey); |
| | | |
| | | // 妿å½åä¸åå¨è¯¥è®¾å¤çç¶æ |
| | | if (currentState == null) |
| | | { |
| | | // å½åä¸åå¨ï¼ç´æ¥æ·»å |
| | | // 为æ°ç¶æè®¾ç½®çæ¬å·ï¼æ¶é´æ³ï¼ |
| | | newState.Version = DateTime.UtcNow.Ticks; |
| | | // ç´æ¥æ·»å å°ç¼å |
| | | _cache.AddObject(cacheKey, newState); |
| | | return true; |
| | | } |
| | | |
| | | // 使ç¨å½ååå¨ççæ¬å·ä½ä¸ºææçæ¬ |
| | | // å½ååå¨ç¶æï¼è®°å½ææçæ¬å·ç¨äºä¹è§éæ£æ¥ |
| | | var expectedVersion = currentState.Version; |
| | | |
| | | // æ´æ°æ°ç¶æççæ¬å·ä¸ºææ°æ¶é´æ³ |
| | | newState.Version = DateTime.UtcNow.Ticks; |
| | | |
| | | // å°è¯å®å
¨æ´æ°ï¼å¦æçæ¬å²çªåè¿å false |
| | | return _cache.TrySafeUpdate( |
| | | cacheKey, |
| | | newState, |
| | |
| | | } |
| | | |
| | | /// <summary> |
| | | /// å
éRobotSocketState对象ï¼å建深æ·è´ï¼ |
| | | /// å
é RobotSocketState å¯¹è±¡ï¼æ·±æ·è´ï¼ |
| | | /// </summary> |
| | | /// <remarks> |
| | | /// ä½¿ç¨ JSON åºåå/ååºååå®ç°æ·±æ·è´ã |
| | | /// è¿æ ·å¯ä»¥ç¡®ä¿æ°å¯¹è±¡ä¸å对象å®å
¨ç¬ç«ï¼ä¿®æ¹æ°å¯¹è±¡ä¸ä¼å½±åå对象ã |
| | | /// </remarks> |
| | | /// <param name="source">æºç¶æå¯¹è±¡</param> |
| | | /// <returns>æ°çç¶æå¯¹è±¡ï¼æ¯æºå¯¹è±¡çæ·±æ·è´</returns> |
| | | public RobotSocketState CloneState(RobotSocketState source) |
| | | { |
| | | // 使ç¨åºåå/ååºååè¿è¡æ·±æ·è´ |
| | | // å°æºå¯¹è±¡åºåå为 JSON å符串 |
| | | var json = JsonConvert.SerializeObject(source); |
| | | // ååºåå为æ°ç RobotSocketState 对象 |
| | | // 妿ååºåå失败ï¼è¿å nullï¼ï¼å建ä¸ä¸ªæ°å¯¹è±¡å¹¶å¤å¶ IPAddress |
| | | return JsonConvert.DeserializeObject<RobotSocketState>(json) ?? new RobotSocketState { IPAddress = source.IPAddress }; |
| | | } |
| | | |
| | | /// <summary> |
| | | /// è·åRedisç¼åé® |
| | | /// è·å Redis ç¼åé® |
| | | /// </summary> |
| | | /// <remarks> |
| | | /// ç¼å鮿 ¼å¼ï¼{RedisPrefix.Code}:{RedisName.SocketDevices}:{ipAddress} |
| | | /// ä¾å¦ï¼Code:SocketDevices:192.168.1.100 |
| | | /// </remarks> |
| | | /// <param name="ipAddress">è®¾å¤ IP å°å</param> |
| | | /// <returns>宿´ç Redis ç¼åé®</returns> |
| | | public static string GetCacheKey(string ipAddress) |
| | | { |
| | | return $"{RedisPrefix.Code}:{RedisName.SocketDevices}:{ipAddress}"; |
| | | } |
| | | |
| | | /// <summary> |
| | | /// ä»ç¼åè·åç¶æ |
| | | /// ä»ç¼åè·åæºæ¢°æç¶æ |
| | | /// </summary> |
| | | /// <param name="ipAddress">è®¾å¤ IP å°å</param> |
| | | /// <returns>妿åå¨åè¿åç¶æå¯¹è±¡ï¼å¦åè¿å null</returns> |
| | | public RobotSocketState? GetState(string ipAddress) |
| | | { |
| | | return _cache.Get<RobotSocketState>(GetCacheKey(ipAddress)); |
| | | } |
| | | |
| | | /// <summary> |
| | | /// è·åæåå»ºç¶æ |
| | | /// è·åæåå»ºæºæ¢°æç¶æ |
| | | /// </summary> |
| | | /// <remarks> |
| | | /// 妿ç¼åä¸å·²åå¨è¯¥è®¾å¤çç¶æï¼ç´æ¥è¿åã |
| | | /// 妿ä¸åå¨ï¼åå建æ°çç¶æå¯¹è±¡å¹¶åå
¥ç¼åï¼ç¶åè¿åã |
| | | /// </remarks> |
| | | /// <param name="ipAddress">è®¾å¤ IP å°å</param> |
| | | /// <param name="robotCrane">æºå¨äººè®¾å¤ä¿¡æ¯ï¼ç¨äºåå§åæ°ç¶æ</param> |
| | | /// <returns>该设å¤çç¶æå¯¹è±¡</returns> |
| | | public RobotSocketState GetOrCreateState(string ipAddress, RobotCraneDevice robotCrane) |
| | | { |
| | | // 使ç¨ç¼åæå¡ç GetOrAdd æ¹æ³ï¼å·¥å彿°å¨ç¼åæªå½ä¸æ¶å建æ°ç¶æ |
| | | return _cache.GetOrAdd(GetCacheKey(ipAddress), _ => new RobotSocketState |
| | | { |
| | | IPAddress = ipAddress, |
| | | RobotCrane = robotCrane |
| | | IPAddress = ipAddress, // 设置 IP å°åä½ä¸ºæ è¯ |
| | | RobotCrane = robotCrane // ä¿å设å¤ä¿¡æ¯ |
| | | }); |
| | | } |
| | | } |
| | |
| | | using Newtonsoft.Json; |
| | | using Newtonsoft.Json; |
| | | using WIDESEA_Core; |
| | | using WIDESEAWCS_Common; |
| | | using WIDESEAWCS_Common.HttpEnum; |
| | | using WIDESEAWCS_Common.TaskEnum; |
| | | using WIDESEAWCS_Core; |
| | | using WIDESEAWCS_Core.Helper; |
| | | using WIDESEAWCS_Core.LogHelper; |
| | | using WIDESEAWCS_DTO.Stock; |
| | | using WIDESEAWCS_DTO.TaskInfo; |
| | | using WIDESEAWCS_ITaskInfoService; |
| | |
| | | namespace WIDESEAWCS_Tasks |
| | | { |
| | | /// <summary> |
| | | /// æºå¨äººä»»å¡å¤çå¨ï¼è´è´£ä»»å¡è·åãä¸åãå
¥åºä»»å¡åä¼ ååºå DTO æå»ºã |
| | | /// æºå¨äººä»»å¡å¤çå¨ - è´è´£ä»»å¡è·åãä¸åãå
¥åºä»»å¡åä¼ ååºå DTO æå»º |
| | | /// </summary> |
| | | /// <remarks> |
| | | /// æ ¸å¿èè´£ï¼ |
| | | /// 1. 仿°æ®åºè½®è¯¢å¾
å¤ççæºå¨äººä»»å¡ |
| | | /// 2. åæºå¨äººå®¢æ·ç«¯ä¸ååè´§æä»¤ï¼Pickbatteryï¼ |
| | | /// 3. å¤çå
¥åºä»»å¡çåä¼ ï¼æç/ç»ç/æ¢çåºæ¯ï¼ |
| | | /// 4. æå»ºåºååä¼ DTO å¹¶è°ç¨ WMS æ¥å£ |
| | | /// |
| | | /// éè¿ç½å
³è®¿é® Socketï¼é¿å
ä¸å¡å±ç´æ¥ä¾èµ TcpSocketServerã |
| | | /// </remarks> |
| | | public class RobotTaskProcessor |
| | | { |
| | | // éè¿ç½å
³è®¿é® Socketï¼é¿å
ä¸å¡å±ç´æ¥ä¾èµ TcpSocketServerã |
| | | /// <summary> |
| | | /// Socket 客æ·ç«¯ç½å
³æ¥å£ |
| | | /// </summary> |
| | | /// <remarks> |
| | | /// éè¿ç½å
³è®¿é® Socketï¼é¿å
ä¸å¡å±ç´æ¥ä¾èµ TcpSocketServerã |
| | | /// æä¾ç»ä¸ç客æ·ç«¯éä¿¡æ¥å£ã |
| | | /// </remarks> |
| | | private readonly ISocketClientGateway _socketClientGateway; |
| | | |
| | | /// <summary> |
| | | /// æºæ¢°æç¶æç®¡çå¨ |
| | | /// </summary> |
| | | private readonly RobotStateManager _stateManager; |
| | | |
| | | /// <summary> |
| | | /// æºå¨äººä»»å¡æå¡ |
| | | /// </summary> |
| | | /// <remarks> |
| | | /// ç¨äºæ¥è¯¢ãæ´æ°ãå 餿ºå¨äººä»»å¡è®°å½ã |
| | | /// </remarks> |
| | | private readonly IRobotTaskService _robotTaskService; |
| | | |
| | | /// <summary> |
| | | /// éç¨ä»»å¡æå¡ |
| | | /// </summary> |
| | | /// <remarks> |
| | | /// ç¨äºä¸ WMS ç³»ç»äº¤äºï¼æ¥æ¶ä»»å¡ãå¤çä»»å¡ç¶æçã |
| | | /// </remarks> |
| | | private readonly ITaskService _taskService; |
| | | |
| | | /// <summary> |
| | | /// HTTP 客æ·ç«¯å¸®å©ç±» |
| | | /// </summary> |
| | | /// <remarks> |
| | | /// ç¨äºè°ç¨ WMS ç³»ç»ç HTTP æ¥å£ã |
| | | /// </remarks> |
| | | private readonly HttpClientHelper _httpClientHelper; |
| | | |
| | | /// <summary> |
| | | /// æé 彿° |
| | | /// </summary> |
| | | /// <param name="socketClientGateway">Socket ç½å
³</param> |
| | | /// <param name="stateManager">ç¶æç®¡çå¨</param> |
| | | /// <param name="robotTaskService">æºå¨äººä»»å¡æå¡</param> |
| | | /// <param name="taskService">éç¨ä»»å¡æå¡</param> |
| | | /// <param name="httpClientHelper">HTTP 客æ·ç«¯å¸®å©ç±»</param> |
| | | public RobotTaskProcessor( |
| | | ISocketClientGateway socketClientGateway, |
| | | RobotStateManager stateManager, |
| | |
| | | } |
| | | |
| | | /// <summary> |
| | | /// æè®¾å¤ç¼ç è·åå½åæºå¨äººä»»å¡ã |
| | | /// æè®¾å¤ç¼ç è·åå½åæºå¨äººçå¾
å¤çä»»å¡ |
| | | /// </summary> |
| | | /// <remarks> |
| | | /// 仿°æ®åºä¸æ¥è¯¢æå®è®¾å¤ç¼ç çå¾
å¤çæºå¨äººä»»å¡ã |
| | | /// åªè¿åç¶æä¸º"å¾
å¤ç"çä»»å¡ã |
| | | /// </remarks> |
| | | /// <param name="robotCrane">æºå¨äººè®¾å¤ä¿¡æ¯ï¼å
å«è®¾å¤ç¼ç </param> |
| | | /// <returns>å¾
å¤ççä»»å¡å¯¹è±¡ï¼å¦ææ²¡æåè¿å null</returns> |
| | | public Dt_RobotTask? GetTask(RobotCraneDevice robotCrane) |
| | | { |
| | | return _robotTaskService.QueryRobotCraneTask(robotCrane.DeviceCode); |
| | | } |
| | | |
| | | /// <summary> |
| | | /// å 餿ºå¨äººä»»å¡ã |
| | | /// å 餿ºå¨äººä»»å¡ |
| | | /// </summary> |
| | | /// <remarks> |
| | | /// å½ä»»å¡å®æï¼æ è®ºæ¯æåè¿æ¯å¤±è´¥ï¼æ¶è°ç¨ï¼å 餿°æ®åºä¸çä»»å¡è®°å½ã |
| | | /// </remarks> |
| | | /// <param name="ID">è¦å é¤çä»»å¡ ID</param> |
| | | /// <returns>å 餿¯å¦æå</returns> |
| | | public bool? DeleteTask(int ID) |
| | | { |
| | | return _robotTaskService.Repository.DeleteDataById(ID); |
| | | } |
| | | |
| | | /// <summary> |
| | | /// ä¸ååè´§æä»¤ï¼Pickbatteryï¼å°æºå¨äººå®¢æ·ç«¯ã |
| | | /// ä¸ååè´§æä»¤ï¼Pickbatteryï¼å°æºå¨äººå®¢æ·ç«¯ |
| | | /// </summary> |
| | | /// <remarks> |
| | | /// åéæ ¼å¼ï¼Pickbattery,{æºå°å} |
| | | /// ä¾å¦ï¼Pickbattery,A01 è¡¨ç¤ºä» A01 ä½ç½®åè´§ |
| | | /// |
| | | /// ä¸åæååï¼ |
| | | /// 1. æ´æ°ä»»å¡ç¶æä¸º"æºå¨äººæ§è¡ä¸" |
| | | /// 2. å°ä»»å¡å
³èå°ç¶æå¯¹è±¡ |
| | | /// 3. å®å
¨æ´æ°ç¶æå° Redis |
| | | /// 4. æ´æ°ä»»å¡è®°å½å°æ°æ®åº |
| | | /// </remarks> |
| | | /// <param name="task">è¦ä¸åçä»»å¡å¯¹è±¡</param> |
| | | /// <param name="state">æºå¨äººå½åç¶æ</param> |
| | | public async Task SendSocketRobotPickAsync(Dt_RobotTask task, RobotSocketState state) |
| | | { |
| | | // æå»ºåè´§æä»¤ï¼æ ¼å¼ï¼Pickbattery,{æºå°å} |
| | | string taskString = $"Pickbattery,{task.RobotSourceAddress}"; |
| | | |
| | | // éè¿ Socket ç½å
³åéæä»¤å°æºå¨äººå®¢æ·ç«¯ |
| | | bool result = await _socketClientGateway.SendToClientAsync(state.IPAddress, taskString); |
| | | |
| | | if (result) |
| | | { |
| | | // åéæåï¼è®°å½æ¥å¿ |
| | | QuartzLogger.Error($"ä¸ååè´§æä»¤ï¼æä»¤: {taskString}", state.RobotCrane.DeviceName); |
| | | |
| | | // æ´æ°ä»»å¡ç¶æä¸º"æºå¨äººæ§è¡ä¸" |
| | | task.RobotTaskState = TaskRobotStatusEnum.RobotExecuting.GetHashCode(); |
| | | |
| | | // å°ä»»å¡å
³èå°ç¶æå¯¹è±¡ |
| | | state.CurrentTask = task; |
| | | |
| | | // ä¿æåè¯ä¹ï¼ä»
å¨ç¶æå®å
¨åå
¥æåååæ´æ°ä»»å¡ç¶æã |
| | | // ä¿æåè¯ä¹ï¼ä»
å¨ç¶æå®å
¨åå
¥æåååæ´æ°ä»»å¡ç¶æ |
| | | // è¿æ ·å¯ä»¥ç¡®ä¿ç¶æåä»»å¡è®°å½çä¸è´æ§ |
| | | if (_stateManager.TryUpdateStateSafely(state.IPAddress, state)) |
| | | { |
| | | await _robotTaskService.UpdateRobotTaskAsync(task); |
| | |
| | | } |
| | | |
| | | /// <summary> |
| | | /// å¤çå
¥åºä»»å¡åä¼ ï¼æç/ç»ç/æ¢çåºæ¯ï¼ã |
| | | /// å¤çå
¥åºä»»å¡åä¼ ï¼æç/ç»ç/æ¢çåºæ¯ï¼ |
| | | /// </summary> |
| | | /// <remarks> |
| | | /// å½åè´§å®æï¼AllPickFinishedï¼ææ¾è´§å®æï¼AllPutFinishedï¼æ¶è°ç¨æ¤æ¹æ³ã |
| | | /// æ ¹æ®ä»»å¡ç±»ååå°åæ¥æºå³å®å¦ä½åä¼ ç» WMSã |
| | | /// |
| | | /// å¤çé»è¾ï¼ |
| | | /// 1. æ ¹æ® useSourceAddress å³å®ä½¿ç¨æºå°åè¿æ¯ç®æ å°å |
| | | /// 2. æ ¹æ®ä»»å¡ç±»åï¼ç»ç/æ¢ç/æçï¼å³å®ä»»å¡ç±»åï¼å
¥åº/空æçå
¥åºï¼ |
| | | /// 3. æå»º CreateTaskDto å¹¶è°ç¨ WMS æ¥å£åå»ºä»»å¡ |
| | | /// 4. æ¥æ¶ WMS è¿åçä»»å¡ä¿¡æ¯ |
| | | /// 5. æ´æ°è¾é线çç®æ å°åãä»»å¡å·ç |
| | | /// </remarks> |
| | | /// <param name="state">æºå¨äººå½åç¶æ</param> |
| | | /// <param name="useSourceAddress">æ¯å¦ä½¿ç¨æºå°åï¼true 表示æç/æ¢çåºæ¯ï¼false 表示ç»ç/æ¢çåºæ¯ï¼</param> |
| | | /// <returns>å¤çæ¯å¦æå</returns> |
| | | public async Task<bool> HandleInboundTaskAsync(RobotSocketState state, bool useSourceAddress) |
| | | { |
| | | // è·åå½åå
³èçä»»å¡ |
| | | var currentTask = state.CurrentTask; |
| | | if (currentTask == null) |
| | | { |
| | | return false; |
| | | } |
| | | |
| | | // è·åå··é代ç |
| | | string roadway = currentTask.RobotSourceAddressLineCode; |
| | | |
| | | // æ ¹æ®å··éåç§°å¤æä»åº ID |
| | | // ZYRB1 -> 1, HPRB001 -> 2, å
¶ä» -> 3 |
| | | int warehouseId = currentTask.RobotRoadway == "ZYRB1" ? 1 : currentTask.RobotRoadway == "HPRB001" ? 2 : 3; |
| | | |
| | | // ä»»å¡ç±»åï¼0 表示æªå®ä¹ï¼ç¨åæ ¹æ®ä»»å¡ç±»åè®¾ç½®ï¼ |
| | | int taskType = 0; |
| | | |
| | | // æºå°ååç®æ å°åï¼åå§åï¼ |
| | | string SourceAddress = currentTask.RobotTargetAddressLineCode; |
| | | string TargetAddress = currentTask.RobotSourceAddressLineCode; |
| | | |
| | | // æç代ç ï¼åå§åä¸ºç©ºï¼ |
| | | string PalletCode = string.Empty; |
| | | |
| | | // è·åä»»å¡ç±»åçæä¸¾å¼ |
| | | var robotTaskType = (RobotTaskTypeEnum)currentTask.RobotTaskType; |
| | | |
| | | // æ ¹æ® useSourceAddress å³å®å¤çé»è¾ |
| | | if (useSourceAddress) |
| | | { |
| | | // ä½¿ç¨æºå°åçåºæ¯ï¼æçãæ¢çï¼æ¾ç©ºæçï¼ |
| | | switch (robotTaskType) |
| | | { |
| | | case RobotTaskTypeEnum.GroupPallet: |
| | | // ç»çä»»å¡ä¸ä½¿ç¨æºå°åï¼ç´æ¥è¿å false |
| | | return false; |
| | | |
| | | case RobotTaskTypeEnum.ChangePallet: |
| | | case RobotTaskTypeEnum.SplitPallet: |
| | | taskType = TaskTypeEnum.InEmpty.GetHashCode(); |
| | | PalletCode = currentTask.RobotSourceAddressPalletCode; |
| | | // æ¢ç/æçåºæ¯ï¼æçéè¦å
¥åº |
| | | taskType = TaskTypeEnum.InEmpty.GetHashCode(); // 空æçå
¥åº |
| | | PalletCode = currentTask.RobotSourceAddressPalletCode; // ä½¿ç¨æºå°åçæçç |
| | | break; |
| | | } |
| | | } |
| | | else |
| | | { |
| | | // 使ç¨ç®æ å°åçåºæ¯ï¼ç»çãæ¢çï¼æåå
¥åºï¼ |
| | | switch (robotTaskType) |
| | | { |
| | | case RobotTaskTypeEnum.ChangePallet: |
| | | case RobotTaskTypeEnum.GroupPallet: |
| | | taskType = TaskTypeEnum.Inbound.GetHashCode(); |
| | | PalletCode = currentTask.RobotTargetAddressPalletCode; |
| | | // æ¢ç/ç»çåºæ¯ï¼è´§ç©éè¦å
¥åº |
| | | taskType = TaskTypeEnum.Inbound.GetHashCode(); // æåå
¥åº |
| | | PalletCode = currentTask.RobotTargetAddressPalletCode; // 使ç¨ç®æ å°åçæçç |
| | | break; |
| | | |
| | | case RobotTaskTypeEnum.SplitPallet: |
| | | // æçä»»å¡ä¸ä½¿ç¨ç®æ å°å |
| | | return true; |
| | | } |
| | | } |
| | | |
| | | // æå»ºå建任å¡ç DTO |
| | | CreateTaskDto taskDto = new CreateTaskDto |
| | | { |
| | | PalletCode = PalletCode, |
| | | SourceAddress = SourceAddress ?? string.Empty, |
| | | TargetAddress = TargetAddress ?? string.Empty, |
| | | Roadway = roadway, |
| | | WarehouseId = warehouseId, |
| | | PalletType = 1, |
| | | TaskType = taskType |
| | | PalletCode = PalletCode, // æçæ¡ç |
| | | SourceAddress = SourceAddress ?? string.Empty, // æºå°å |
| | | TargetAddress = TargetAddress ?? string.Empty, // ç®æ å°å |
| | | Roadway = roadway, // å··é |
| | | WarehouseId = warehouseId, // ä»åº ID |
| | | PalletType = 1, // æçç±»åï¼é»è®¤ä¸º1ï¼ |
| | | TaskType = taskType // ä»»å¡ç±»åï¼å
¥åº/空æçå
¥åºï¼ |
| | | }; |
| | | |
| | | // è°ç¨ WMS æ¥å£å建å
¥åºä»»å¡ |
| | | var result = _httpClientHelper.Post<WebResponseContent>(nameof(ConfigKey.CreateTaskInboundAsync), taskDto.ToJson()); |
| | | |
| | | // 妿è°ç¨å¤±è´¥æè¿åéè¯¯ç¶æ |
| | | if (!result.Data.Status && result.IsSuccess) |
| | | { |
| | | return false; |
| | | } |
| | | |
| | | // è§£æ WMS è¿åçä»»å¡ä¿¡æ¯ |
| | | WMSTaskDTO taskDTO = JsonConvert.DeserializeObject<WMSTaskDTO>(result.Data.Data.ToJson() ?? string.Empty) ?? new WMSTaskDTO(); |
| | | |
| | | // è°ç¨ä»»å¡æå¡æ¥æ¶ WMS ä»»å¡ |
| | | var content = _taskService.ReceiveWMSTask(new List<WMSTaskDTO> { taskDTO }); |
| | | if (!content.Status) |
| | | { |
| | | return false; |
| | | } |
| | | |
| | | // è§£æè¿åçä»»å¡ä¿¡æ¯ |
| | | var taskInfo = JsonConvert.DeserializeObject<Dt_Task>(content.Data.ToJson() ?? string.Empty) ?? new Dt_Task(); |
| | | |
| | | // è·åæºå°å |
| | | string sourceAddress = taskDTO.SourceAddress; |
| | | |
| | | // æ¥æ¾æºå°å对åºçè¾éçº¿è®¾å¤ |
| | | IDevice? device = Storage.Devices.FirstOrDefault(x => x.DeviceProDTOs.Any(d => d.DeviceChildCode == sourceAddress)); |
| | | |
| | | if (device != null) |
| | | { |
| | | // å°è®¾å¤è½¬æ¢ä¸ºè¾é线类å |
| | | CommonConveyorLine conveyorLine = (CommonConveyorLine)device; |
| | | |
| | | // 设置è¾é线çç®æ å°å |
| | | conveyorLine.SetValue(ConveyorLineDBNameNew.Target, taskInfo.NextAddress, sourceAddress); |
| | | |
| | | // 设置è¾é线çä»»å¡å· |
| | | conveyorLine.SetValue(ConveyorLineDBNameNew.TaskNo, taskInfo.TaskNum, sourceAddress); |
| | | |
| | | // 触åè¾é线å¼å§æ§è¡ï¼åå
¥ WCS_STB = 1ï¼ |
| | | conveyorLine.SetValue(ConveyorLineDBNameNew.WCS_STB, 1, sourceAddress); |
| | | |
| | | // æ´æ°ä»»å¡ç¶æå°ä¸ä¸é¶æ®µ |
| | | if (_taskService.UpdateTaskStatusToNext(taskInfo).Status) |
| | | { |
| | | return true; |
| | |
| | | } |
| | | |
| | | /// <summary> |
| | | /// æå»ºåºååä¼ DTOã |
| | | /// æå»ºåºååä¼ DTO |
| | | /// </summary> |
| | | /// <remarks> |
| | | /// ç¨äºæçåç»çæä½æ¶ï¼å WMS åä¼ åºåä¿¡æ¯ã |
| | | /// DTO å
嫿ºè´§ä½ãç®æ è´§ä½ãæçç ä»¥åæ¯ä¸ªä½ç½®ççµæ± æ¡ç ã |
| | | /// </remarks> |
| | | /// <param name="state">æºå¨äººå½åç¶æ</param> |
| | | /// <param name="positions">çµæ± ä½ç½®æ°ç»</param> |
| | | /// <returns>æå»ºå¥½çåºå DTO</returns> |
| | | public static StockDTO BuildStockDTO(RobotSocketState state, int[] positions) |
| | | { |
| | | return new StockDTO |
| | | { |
| | | // æºè¾é线ç¼å· |
| | | SourceLineNo = state.CurrentTask.RobotSourceAddressLineCode, |
| | | |
| | | // æºæçå· |
| | | SourcePalletNo = state.CurrentTask.RobotSourceAddressPalletCode, |
| | | |
| | | // ç®æ æçå· |
| | | TargetPalletNo = state.CurrentTask.RobotTargetAddressPalletCode, |
| | | |
| | | // ç®æ è¾é线ç¼å· |
| | | TargetLineNo = state.CurrentTask.RobotTargetAddressLineCode, |
| | | |
| | | // çµæ± ä½ç½®è¯¦æ
å表 |
| | | // è¿æ»¤æä½ç½®ä¸º 0 æè´æ°çæ ææ°æ® |
| | | // æä½ç½®ç¼å·æåº |
| | | // 为æ¯ä¸ªä½ç½®çæå¯¹åºçåºå详æ
|
| | | Details = positions |
| | | .Where(x => x > 0) |
| | | .OrderBy(x => x) |
| | | .Where(x => x > 0) // è¿æ»¤æ æä½ç½® |
| | | .OrderBy(x => x) // æä½ç½®æåº |
| | | .Select((x, idx) => new StockDetailDTO |
| | | { |
| | | // æ°éï¼å¦æå·²æä»»å¡æ»æ°ï¼ä½¿ç¨ä»»å¡æ»æ°+å½åä½ç½®æ°ï¼å¦ååªä½¿ç¨å½åä½ç½®æ° |
| | | Quantity = state.RobotTaskTotalNum > 0 ? state.RobotTaskTotalNum + positions.Length : positions.Length, |
| | | |
| | | // éé/ä½ç½®ç¼å· |
| | | Channel = x, |
| | | |
| | | // çµæ± æ¡ç ï¼å¦æç¶æä¸ææ¡ç å表ï¼å对åºä½ç½®çæ¡ç ï¼å¦å为空 |
| | | CellBarcode = state.CellBarcode?.Count > 0 ? state.CellBarcode[x - 1] : "" |
| | | }) |
| | | .ToList() |
| | |
| | | } |
| | | |
| | | /// <summary> |
| | | /// è°ç¨æç APIã |
| | | /// è°ç¨æç API |
| | | /// </summary> |
| | | /// <remarks> |
| | | /// å½åè´§å®æä¸éè¦æçæ¶è°ç¨ã |
| | | /// å°çµæ± 仿çä¸åä¸ï¼é个æ¾ç½®å°ç®æ ä½ç½®ã |
| | | /// </remarks> |
| | | /// <param name="stockDTO">åºå DTOï¼å
å«è¦æçççµè¯ä¿¡æ¯</param> |
| | | /// <returns>HTTP ååºç»æ</returns> |
| | | public HttpResponseResult<WebResponseContent> PostSplitPalletAsync(StockDTO stockDTO) |
| | | { |
| | | return _httpClientHelper.Post<WebResponseContent>(nameof(ConfigKey.SplitPalletAsync), stockDTO.ToJson()); |
| | | } |
| | | |
| | | /// <summary> |
| | | /// è°ç¨ç»ç/æ¢ç APIã |
| | | /// è°ç¨ç»ç/æ¢ç API |
| | | /// </summary> |
| | | /// <remarks> |
| | | /// 彿¾è´§å®æä¸éè¦ç»çææ¢çæ¶è°ç¨ã |
| | | /// å°å¤ä¸ªçµæ± ç»åå°åä¸ä¸ªæçä¸ã |
| | | /// |
| | | /// configKey åæ°å³å®è°ç¨åªä¸ª APIï¼ |
| | | /// - GroupPalletAsync: ç»çæ¥å£ |
| | | /// - ChangePalletAsync: æ¢çæ¥å£ |
| | | /// </remarks> |
| | | /// <param name="configKey">é
ç½®é®åï¼å³å®è°ç¨åªä¸ª API</param> |
| | | /// <param name="stockDTO">åºå DTOï¼å
å«è¦ç»çççµè¯ä¿¡æ¯</param> |
| | | /// <returns>HTTP ååºç»æ</returns> |
| | | public HttpResponseResult<WebResponseContent> PostGroupPalletAsync(string configKey, StockDTO stockDTO) |
| | | { |
| | | return _httpClientHelper.Post<WebResponseContent>(configKey, stockDTO.ToJson()); |
| | |
| | | using System.Net.Sockets; |
| | | using System.Net.Sockets; |
| | | using WIDESEAWCS_Common.HttpEnum; |
| | | using WIDESEAWCS_Common.TaskEnum; |
| | | using WIDESEAWCS_DTO.TaskInfo; |
| | |
| | | namespace WIDESEAWCS_Tasks.Workflow |
| | | { |
| | | /// <summary> |
| | | /// åç¼å½ä»¤å¤çï¼è¿ç§»å RobotMessageHandler ç pickfinished/putfinished 忝ã |
| | | /// åç¼å½ä»¤å¤çå¨ |
| | | /// </summary> |
| | | /// <remarks> |
| | | /// è¿ç§»å RobotMessageHandler ç pickfinished/putfinished 忝ã |
| | | /// |
| | | /// åç¼å½ä»¤æ¯æä»¥ç¹å®åç¼å¼å¤´çå½ä»¤ï¼åé¢è·ééå·åéçåæ°ã |
| | | /// æ ¼å¼ï¼{åç¼},{åæ°1},{åæ°2},... |
| | | /// |
| | | /// å½åæ¯æçåç¼å½ä»¤ï¼ |
| | | /// - pickfinished: åè´§å®æï¼åé¢è·é宿çä½ç½®ç¼å·å表 |
| | | /// - putfinished: æ¾è´§å®æï¼åé¢è·é宿çä½ç½®ç¼å·å表 |
| | | /// |
| | | /// è¿äºå½ä»¤é常å
å«åè´§ææ¾è´§çä½ç½®ä¿¡æ¯ï¼éè¦è§£æå¹¶æ´æ°ç¶æã |
| | | /// </remarks> |
| | | public class RobotPrefixCommandHandler : IRobotPrefixCommandHandler |
| | | { |
| | | /// <summary> |
| | | /// æºå¨äººä»»å¡æå¡ |
| | | /// </summary> |
| | | /// <remarks> |
| | | /// ç¨äºæ¥è¯¢åæ´æ°ä»»å¡è®°å½ã |
| | | /// </remarks> |
| | | private readonly IRobotTaskService _robotTaskService; |
| | | |
| | | /// <summary> |
| | | /// ä»»å¡å¤çå¨ |
| | | /// </summary> |
| | | /// <remarks> |
| | | /// ç¨äºå¤çåè´§/æ¾è´§å®ææ¶çä¸å¡é»è¾ï¼å¦è°ç¨æç/ç»ç APIã |
| | | /// </remarks> |
| | | private readonly RobotTaskProcessor _taskProcessor; |
| | | |
| | | /// <summary> |
| | | /// ç¶æç®¡çå¨ |
| | | /// </summary> |
| | | /// <remarks> |
| | | /// ç¨äºå®å
¨æ´æ°æºå¨äººçç¶æã |
| | | /// </remarks> |
| | | private readonly RobotStateManager _stateManager; |
| | | |
| | | /// <summary> |
| | | /// Socket ç½å
³ |
| | | /// </summary> |
| | | /// <remarks> |
| | | /// ç¨äºå客æ·ç«¯åéååºæ¶æ¯ã |
| | | /// </remarks> |
| | | private readonly ISocketClientGateway _socketClientGateway; |
| | | |
| | | /// <summary> |
| | | /// æé 彿° |
| | | /// </summary> |
| | | /// <param name="robotTaskService">任塿å¡</param> |
| | | /// <param name="taskProcessor">ä»»å¡å¤çå¨</param> |
| | | /// <param name="stateManager">ç¶æç®¡çå¨</param> |
| | | /// <param name="socketClientGateway">Socket ç½å
³</param> |
| | | public RobotPrefixCommandHandler( |
| | | IRobotTaskService robotTaskService, |
| | | RobotTaskProcessor taskProcessor, |
| | |
| | | _socketClientGateway = socketClientGateway; |
| | | } |
| | | |
| | | /// <summary> |
| | | /// æ£æ¥æ¶æ¯æ¯å¦ä¸ºåç¼å½ä»¤ |
| | | /// </summary> |
| | | /// <remarks> |
| | | /// åç¼å½ä»¤å¿
须以 "pickfinished" æ "putfinished" å¼å¤´ï¼ä¸åºå大å°åï¼ã |
| | | /// </remarks> |
| | | /// <param name="message">æ¶æ¯å
容ï¼å°åå½¢å¼ï¼</param> |
| | | /// <returns>å¦ææ¯æç¼å½ä»¤è¿å true</returns> |
| | | public bool IsPrefixCommand(string message) |
| | | { |
| | | // æ£æ¥æ¶æ¯æ¯å¦ä»¥ pickfinished æ putfinished å¼å¤´ |
| | | return message.StartsWith("pickfinished") || message.StartsWith("putfinished"); |
| | | } |
| | | |
| | | /// <summary> |
| | | /// å¤çåç¼å½ä»¤ |
| | | /// </summary> |
| | | /// <remarks> |
| | | /// å¤çæµç¨ï¼ |
| | | /// 1. è§£ææ¶æ¯ï¼æåä½ç½®åæ° |
| | | /// 2. æ¥è¯¢å½åä»»å¡ |
| | | /// 3. æ ¹æ®å½ä»¤ç±»åè°ç¨ç¸åºçå¤çæ¹æ³ |
| | | /// 4. åååæ¶æ¯å°å®¢æ·ç«¯ |
| | | /// |
| | | /// æ¶æ¯æ ¼å¼ï¼{å½ä»¤åç¼},{ä½ç½®1},{ä½ç½®2},... |
| | | /// 示ä¾ï¼pickfinished,1,2,3 表示åè´§å®æï¼ä½ç½® 1ã2ã3 çè´§ç©å·²åèµ° |
| | | /// </remarks> |
| | | /// <param name="message">åå§æ¶æ¯å
容</param> |
| | | /// <param name="state">æºå¨äººå½åç¶æ</param> |
| | | /// <param name="client">TCP 客æ·ç«¯è¿æ¥ï¼ç¨äºåéååº</param> |
| | | public async Task HandleAsync(string message, RobotSocketState state, TcpClient client) |
| | | { |
| | | try |
| | | { |
| | | // æéå·åéæ¶æ¯ï¼æåå½ä»¤ååæ° |
| | | // ä¾å¦ï¼pickfinished,1,2,3 -> ["pickfinished", "1", "2", "3"] |
| | | var parts = message.Split(','); |
| | | |
| | | // æ£æ¥æ¶æ¯æ ¼å¼æ¯å¦ææï¼è³å°è¦æå½ä»¤åç¼ï¼ä¸ç¶æä¸æå½åä»»å¡ |
| | | if (parts.Length < 1 || state.CurrentTask == null) |
| | | { |
| | | return; |
| | | } |
| | | |
| | | // æåå½ä»¤åç¼å¹¶è½¬æ¢ä¸ºå°å |
| | | var cmd = parts[0].ToLowerInvariant(); |
| | | |
| | | // è§£æä½ç½®åæ°ï¼è·³è¿å½ä»¤åç¼ï¼å¤çåé¢çæ°åï¼ |
| | | // è¿æ»¤ææ æ³è§£æä¸ºæ°åæå¼ä¸º 0 çä½ç½® |
| | | int[] positions = parts.Skip(1) |
| | | .Select(p => int.TryParse(p, out int value) ? value : (int?)null) |
| | | .Where(v => v.HasValue && v.Value != 0) |
| | | .Select(v => v!.Value) |
| | | .Select(p => int.TryParse(p, out int value) ? value : (int?)null) // å°è¯è§£æä¸ºæ´æ° |
| | | .Where(v => v.HasValue && v.Value != 0) // è¿æ»¤æ null å 0 |
| | | .Select(v => v!.Value) // æåå¼ï¼å·²ç¥é nullï¼ |
| | | .ToArray(); |
| | | |
| | | // 仿°æ®åºéæ°æ¥è¯¢å½åä»»å¡ï¼ç¡®ä¿è·åææ°ç¶æï¼ |
| | | var task = await _robotTaskService.Repository.QueryFirstAsync(x => x.RobotTaskId == state.CurrentTask.RobotTaskId); |
| | | |
| | | // æ ¹æ®å½ä»¤åç¼ååå¤ç |
| | | if (cmd.StartsWith("pickfinished")) |
| | | { |
| | | // å¤çåè´§å®æ |
| | | await HandlePickFinishedAsync(state, positions, task); |
| | | } |
| | | else if (cmd.StartsWith("putfinished")) |
| | | { |
| | | // å¤çæ¾è´§å®æ |
| | | await HandlePutFinishedAsync(state, positions, task); |
| | | } |
| | | |
| | | // åååæ¶æ¯å°å®¢æ·ç«¯ï¼ä¿æåæè¡ä¸ºï¼ |
| | | await _socketClientGateway.SendMessageAsync(client, message); |
| | | } |
| | | catch (Exception ex) |
| | | { |
| | | // æè·å¹¶è®°å½å¼å¸¸ï¼é²æ¢å¼å¸¸åä¸ä¼ æå¯¼è´æ¶æ¯å¤ç䏿 |
| | | Console.WriteLine($"RobotJob MessageReceived Error: {ex.Message}"); |
| | | } |
| | | } |
| | | |
| | | /// <summary> |
| | | /// å¤çåè´§å®æï¼pickfinishedï¼å½ä»¤ |
| | | /// </summary> |
| | | /// <remarks> |
| | | /// å¤çé»è¾ï¼ |
| | | /// 1. å¦ææ¯æçä»»å¡ï¼æå»ºåºå DTO å¹¶è°ç¨æç API |
| | | /// 2. æ´æ°å½åå¨ä½ä¸º"åè´§å®æ" |
| | | /// 3. è®°å½åè´§å®æçä½ç½® |
| | | /// 4. æ´æ°ä»»å¡ç¶æä¸º"æºå¨äººåè´§å®æ" |
| | | /// 5. å®å
¨æ´æ°ç¶æå° Redis |
| | | /// </remarks> |
| | | /// <param name="state">æºå¨äººå½åç¶æ</param> |
| | | /// <param name="positions">åè´§å®æçä½ç½®ç¼å·æ°ç»</param> |
| | | /// <param name="task">æºå¨äººä»»å¡è®°å½</param> |
| | | private async Task HandlePickFinishedAsync(RobotSocketState state, int[] positions, Dt_RobotTask? task) |
| | | { |
| | | // å¦ææ¯æçä»»å¡ |
| | | if (state.IsSplitPallet) |
| | | { |
| | | // æå»ºåºå DTOï¼å
å«ä½ç½®ä¿¡æ¯åæçæ¡ç |
| | | var stockDTO = RobotTaskProcessor.BuildStockDTO(state, positions); |
| | | |
| | | // è®°å½åè´§å®æçä½ç½® |
| | | state.LastPickPositions = positions; |
| | | |
| | | // è°ç¨æç API |
| | | var result = _taskProcessor.PostSplitPalletAsync(stockDTO); |
| | | |
| | | // 妿 API è°ç¨æå |
| | | if (result.Data.Status && result.IsSuccess) |
| | | { |
| | | // æ´æ°å½åå¨ä½ä¸º"åè´§å®æ" |
| | | state.CurrentAction = "PickFinished"; |
| | | } |
| | | } |
| | | else |
| | | { |
| | | // éæçä»»å¡ï¼ç´æ¥æ´æ°å¨ä½ |
| | | state.CurrentAction = "PickFinished"; |
| | | } |
| | | |
| | | // è®°å½åè´§å®æçä½ç½®ï¼æ 论æ¯å¦æçé½è®°å½ï¼ |
| | | state.LastPickPositions = positions; |
| | | |
| | | // 妿任å¡åå¨ |
| | | if (task != null) |
| | | { |
| | | // æ´æ°ä»»å¡ç¶æä¸º"æºå¨äººåè´§å®æ" |
| | | task.RobotTaskState = TaskRobotStatusEnum.RobotPickFinish.GetHashCode(); |
| | | |
| | | // å®å
¨æ´æ°ç¶æå° Redisï¼ç¡®ä¿æ´æ°æåååæ´æ°æ°æ®åº |
| | | if (_stateManager.TryUpdateStateSafely(state.IPAddress, state)) |
| | | { |
| | | await _robotTaskService.Repository.UpdateDataAsync(task); |
| | |
| | | } |
| | | } |
| | | |
| | | /// <summary> |
| | | /// å¤çæ¾è´§å®æï¼putfinishedï¼å½ä»¤ |
| | | /// </summary> |
| | | /// <remarks> |
| | | /// å¤çé»è¾ï¼ |
| | | /// 1. 妿æ¯ç»çä»»å¡ï¼æå»ºåºå DTO å¹¶è°ç¨ç»ç/æ¢ç API |
| | | /// 2. 妿ç»çæåï¼å¢å ä»»å¡è®¡æ° |
| | | /// 3. æ´æ°å½åå¨ä½ä¸º"æ¾è´§å®æ" |
| | | /// 4. æ´æ°ä»»å¡ç¶æä¸º"æºå¨äººæ¾è´§å®æ" |
| | | /// 5. å®å
¨æ´æ°ç¶æå° Redis |
| | | /// </remarks> |
| | | /// <param name="state">æºå¨äººå½åç¶æ</param> |
| | | /// <param name="positions">æ¾è´§å®æçä½ç½®ç¼å·æ°ç»</param> |
| | | /// <param name="task">æºå¨äººä»»å¡è®°å½</param> |
| | | private async Task HandlePutFinishedAsync(RobotSocketState state, int[] positions, Dt_RobotTask? task) |
| | | { |
| | | // å设æ¾è´§æåï¼å¦æåç» API è°ç¨å¤±è´¥ä¹ä¸åé计æ°ï¼ |
| | | bool putSuccess = true; |
| | | |
| | | // 妿æ¯ç»çä»»å¡ï¼å
嫿¢çï¼ |
| | | if (state.IsGroupPallet) |
| | | { |
| | | // è®°å½æ¾è´§å®æçä½ç½® |
| | | state.LastPutPositions = positions; |
| | | |
| | | // æå»ºåºå DTO |
| | | var stockDTO = RobotTaskProcessor.BuildStockDTO(state, positions); |
| | | |
| | | // æ ¹æ®ä»»å¡ç±»åå³å®è°ç¨åªä¸ª API |
| | | // æ¢çä»»å¡è°ç¨ ChangePalletAsyncï¼ç»çä»»å¡è°ç¨ GroupPalletAsync |
| | | var configKey = state.CurrentTask?.RobotTaskType == RobotTaskTypeEnum.ChangePallet.GetHashCode() |
| | | ? nameof(ConfigKey.ChangePalletAsync) |
| | | : nameof(ConfigKey.GroupPalletAsync); |
| | | |
| | | // è°ç¨ç»ç/æ¢ç API |
| | | var result = _taskProcessor.PostGroupPalletAsync(configKey, stockDTO); |
| | | |
| | | // æ£æ¥ API è¿åç¶æ |
| | | putSuccess = result.Data.Status && result.IsSuccess; |
| | | } |
| | | |
| | | // 妿æ¾è´§æå |
| | | if (putSuccess) |
| | | { |
| | | // æ´æ°å½åå¨ä½ä¸º"æ¾è´§å®æ" |
| | | state.CurrentAction = "PutFinished"; |
| | | |
| | | // å¢å ä»»å¡è®¡æ°ï¼ç´¯å æ¬æ¬¡å®æçæ°éï¼ |
| | | state.RobotTaskTotalNum += positions.Length; |
| | | |
| | | // 妿任å¡åå¨ï¼åæ¥æ´æ°ä»»å¡çè®¡æ° |
| | | if (task != null) |
| | | { |
| | | task.RobotTaskTotalNum += positions.Length; |
| | | } |
| | | } |
| | | |
| | | // 妿任å¡åå¨ |
| | | if (task != null) |
| | | { |
| | | // æ´æ°ä»»å¡ç¶æä¸º"æºå¨äººæ¾è´§å®æ" |
| | | task.RobotTaskState = TaskRobotStatusEnum.RobotPutFinish.GetHashCode(); |
| | | |
| | | // å®å
¨æ´æ°ç¶æå° Redis |
| | | if (_stateManager.TryUpdateStateSafely(state.IPAddress, state)) |
| | | { |
| | | await _robotTaskService.Repository.UpdateDataAsync(task); |
| | |
| | | using WIDESEAWCS_Common.TaskEnum; |
| | | using WIDESEAWCS_Common.TaskEnum; |
| | | using WIDESEAWCS_Tasks.Workflow.Abstractions; |
| | | |
| | | namespace WIDESEAWCS_Tasks.Workflow |
| | | { |
| | | /// <summary> |
| | | /// ç®åå½ä»¤å¤çï¼ä»
è¿ç§»å RobotMessageHandler ä¸çå½ä»¤åæ¯ï¼ä¸æ¹åä¸å¡è¯ä¹ã |
| | | /// ç®åå½ä»¤å¤çå¨ |
| | | /// </summary> |
| | | /// <remarks> |
| | | /// è¿ç§»å RobotMessageHandler ä¸çç®åå½ä»¤åæ¯ï¼ä¸æ¹åä¸å¡è¯ä¹ã |
| | | /// |
| | | /// ç®åå½ä»¤æ¯æä¸éè¦é¢å¤åæ°çç¶ææ´æ°å½ä»¤ï¼å¦è¿è¡ç¶æã模å¼åæ¢çã |
| | | /// ä¸åç¼å½ä»¤ï¼éè¦è§£æä½ç½®åæ°ï¼ç¸å¯¹ã |
| | | /// |
| | | /// å¤ç宿åè¿å trueï¼æ æ³è¯å«çå½ä»¤è¿å falseã |
| | | /// </remarks> |
| | | public class RobotSimpleCommandHandler : IRobotSimpleCommandHandler |
| | | { |
| | | /// <summary> |
| | | /// æºå¨äººä»»å¡å¤çå¨ |
| | | /// </summary> |
| | | /// <remarks> |
| | | /// ç¨äºå¤ç allpickfinished å allputfinished å½ä»¤æ¶ï¼ |
| | | /// è°ç¨ä»»å¡å
¥åºåå é¤é»è¾ã |
| | | /// </remarks> |
| | | private readonly RobotTaskProcessor _taskProcessor; |
| | | |
| | | /// <summary> |
| | | /// æé 彿° |
| | | /// </summary> |
| | | /// <param name="taskProcessor">ä»»å¡å¤çå¨å®ä¾</param> |
| | | public RobotSimpleCommandHandler(RobotTaskProcessor taskProcessor) |
| | | { |
| | | _taskProcessor = taskProcessor; |
| | | } |
| | | |
| | | /// <summary> |
| | | /// å¤çç®åå½ä»¤ |
| | | /// </summary> |
| | | /// <remarks> |
| | | /// æ ¹æ®æ¶æ¯å
å®¹æ´æ°æºå¨äººçè¿è¡ç¶æã模å¼ãæè对象ç屿§ã |
| | | /// æäºå½ä»¤ï¼å¦ allpickfinishedãallputfinishedï¼ä¼è§¦åå®é
çä¸å¡é»è¾ã |
| | | /// |
| | | /// å½ä»¤åè¡¨ï¼ |
| | | /// - homing: åé¶ä¸ |
| | | /// - homed: å·²åé¶ |
| | | /// - running: è¿è¡ä¸ |
| | | /// - pausing: æåä¸ |
| | | /// - warming: é¢çä¸ |
| | | /// - emstoping: æ¥åä¸ |
| | | /// - picking: åè´§ä¸ |
| | | /// - puting: æ¾è´§ä¸ |
| | | /// - runmode,1: è¿è¡æ¨¡å¼åæ¢å°æå¨ |
| | | /// - runmode,2: è¿è¡æ¨¡å¼åæ¢å°èªå¨ |
| | | /// - controlmode,1: æ§å¶æ¨¡å¼åæ¢å°å®¢æ·ç«¯æ§å¶ |
| | | /// - controlmode,2: æ§å¶æ¨¡å¼åæ¢å°å
¶ä» |
| | | /// - armobject,1: æèæç©æ |
| | | /// - armobject,0: æèæ ç©æ |
| | | /// - allpickfinished: å
¨é¨åè´§å®æ |
| | | /// - allputfinished: å
¨é¨æ¾è´§å®æ |
| | | /// </remarks> |
| | | /// <param name="message">æ¶æ¯å
容ï¼å°åå½¢å¼ï¼</param> |
| | | /// <param name="state">æºå¨äººå½åç¶æï¼ä¼è¢«ä¿®æ¹ï¼</param> |
| | | /// <returns>æ¯å¦æåå¤çï¼æ æ³è¯å«çå½ä»¤è¿å false</returns> |
| | | public async Task<bool> HandleAsync(string message, RobotSocketState state) |
| | | { |
| | | // ä½¿ç¨ switch 表达å¼è¿è¡æ¨¡å¼å¹é
ï¼æé«å¯è¯»æ§åæ§è½ |
| | | switch (message) |
| | | { |
| | | // ==================== è¿è¡ç¶æå½ä»¤ ==================== |
| | | |
| | | // æºå¨äººæ£å¨åé¶ |
| | | case "homing": |
| | | state.OperStatus = "Homing"; |
| | | return true; |
| | | |
| | | // æºå¨äººå·²å®æåé¶ |
| | | case "homed": |
| | | state.OperStatus = "Homed"; |
| | | return true; |
| | | |
| | | // æºå¨äººæ£å¨åè´§ |
| | | case "picking": |
| | | state.CurrentAction = "Picking"; |
| | | return true; |
| | | |
| | | // æºå¨äººæ£å¨æ¾è´§ |
| | | case "puting": |
| | | state.CurrentAction = "Putting"; |
| | | return true; |
| | | |
| | | // ==================== å
¨é¨å®æå½ä»¤ ==================== |
| | | |
| | | // å
¨é¨åè´§å®æ |
| | | case "allpickfinished": |
| | | { |
| | | // æ´æ°å½åå¨ä½ä¸º"å
¨é¨åè´§å®æ" |
| | | state.CurrentAction = "AllPickFinished"; |
| | | |
| | | // è·åå½åå
³èçä»»å¡ |
| | | var currentTask = state.CurrentTask; |
| | | if (currentTask == null) |
| | | { |
| | | // 没æä»»å¡å
³èï¼è¿å false |
| | | return false; |
| | | } |
| | | |
| | | // 夿任å¡ç±»å |
| | | var robotTaskType = (RobotTaskTypeEnum)currentTask.RobotTaskType; |
| | | |
| | | // åªææçææ¢çä»»å¡éè¦å¤çå
¥åº |
| | | if (robotTaskType == RobotTaskTypeEnum.SplitPallet || robotTaskType == RobotTaskTypeEnum.ChangePallet) |
| | | { |
| | | // å¤çå
¥åºä»»å¡åä¼ |
| | | // useSourceAddress: true è¡¨ç¤ºä½¿ç¨æºå°åï¼æç/æ¢çåºæ¯ï¼ |
| | | if (await _taskProcessor.HandleInboundTaskAsync(state, useSourceAddress: true)) |
| | | { |
| | | // å
¥åºæåï¼å é¤ä»»å¡è®°å½ |
| | | _taskProcessor.DeleteTask(currentTask.RobotTaskId); |
| | | return true; |
| | | } |
| | |
| | | return false; |
| | | } |
| | | |
| | | // å
¨é¨æ¾è´§å®æ |
| | | case "allputfinished": |
| | | { |
| | | // æ´æ°å½åå¨ä½ä¸º"å
¨é¨æ¾è´§å®æ" |
| | | state.CurrentAction = "AllPutFinished"; |
| | | |
| | | // è·åå½åå
³èçä»»å¡ |
| | | var currentTask = state.CurrentTask; |
| | | if (currentTask == null) |
| | | { |
| | | return false; |
| | | } |
| | | |
| | | // 夿任å¡ç±»å |
| | | var robotTaskType = (RobotTaskTypeEnum)currentTask.RobotTaskType; |
| | | |
| | | // åªæç»çææ¢çä»»å¡éè¦å¤çå
¥åº |
| | | if (robotTaskType == RobotTaskTypeEnum.GroupPallet || robotTaskType == RobotTaskTypeEnum.ChangePallet) |
| | | { |
| | | // å¤çå
¥åºä»»å¡åä¼ |
| | | // useSourceAddress: false 表示使ç¨ç®æ å°åï¼ç»ç/æ¢çåºæ¯ï¼ |
| | | if (await _taskProcessor.HandleInboundTaskAsync(state, useSourceAddress: false)) |
| | | { |
| | | // å
¥åºæåï¼å é¤ä»»å¡è®°å½ |
| | | _taskProcessor.DeleteTask(currentTask.RobotTaskId); |
| | | state.CurrentTask = null; |
| | | state.RobotTaskTotalNum = 0; |
| | | state.CellBarcode = new List<string>(); |
| | | |
| | | // æ¸
çç¶æï¼ä¸ºä¸ä¸ä¸ªä»»å¡ååå¤ |
| | | state.CurrentTask = null; // æ¸
é¤å½åä»»å¡ |
| | | state.RobotTaskTotalNum = 0; // é置任å¡è®¡æ° |
| | | state.CellBarcode = new List<string>(); // æ¸
空æ¡ç å表 |
| | | return true; |
| | | } |
| | | } |
| | | return false; |
| | | } |
| | | |
| | | // ==================== è¿è¡ç¶æå½ä»¤ï¼ç»ï¼ ==================== |
| | | |
| | | // æºå¨äººæ£å¨è¿è¡ |
| | | case "running": |
| | | state.OperStatus = "Running"; |
| | | return true; |
| | | |
| | | // æºå¨äººæ£å¨æå |
| | | case "pausing": |
| | | state.OperStatus = "Pausing"; |
| | | return true; |
| | | |
| | | // æºå¨äººæ£å¨é¢ç |
| | | case "warming": |
| | | state.OperStatus = "Warming"; |
| | | return true; |
| | | |
| | | // æºå¨äººæ£å¨æ¥å |
| | | case "emstoping": |
| | | state.OperStatus = "Emstoping"; |
| | | return true; |
| | | |
| | | // ==================== 模å¼åæ¢å½ä»¤ ==================== |
| | | |
| | | // è¿è¡æ¨¡å¼åæ¢ä¸ºæå¨ï¼æ¨¡å¼1ï¼ |
| | | case "runmode,1": |
| | | state.RobotRunMode = 1; |
| | | return true; |
| | | |
| | | // è¿è¡æ¨¡å¼åæ¢ä¸ºèªå¨ï¼æ¨¡å¼2ï¼ |
| | | case "runmode,2": |
| | | state.RobotRunMode = 2; |
| | | return true; |
| | | |
| | | // æ§å¶æ¨¡å¼åæ¢ä¸ºå®¢æ·ç«¯æ§å¶ï¼æ¨¡å¼1ï¼ |
| | | case "controlmode,1": |
| | | state.RobotControlMode = 1; |
| | | return true; |
| | | |
| | | // æ§å¶æ¨¡å¼åæ¢ä¸ºå
¶ä»ï¼æ¨¡å¼2ï¼ |
| | | case "controlmode,2": |
| | | state.RobotControlMode = 2; |
| | | return true; |
| | | |
| | | // ==================== æè对象å½ä»¤ ==================== |
| | | |
| | | // æèæç©æï¼æåå°è´§ç©ï¼ |
| | | case "armobject,1": |
| | | state.RobotArmObject = 1; |
| | | return true; |
| | | |
| | | // æèæ ç©æï¼æè空é²ï¼ |
| | | case "armobject,0": |
| | | state.RobotArmObject = 0; |
| | | return true; |
| | | |
| | | // ==================== é»è®¤æ
åµ ==================== |
| | | |
| | | // æ æ³è¯å«çå½ä»¤ï¼è¿å false |
| | | default: |
| | | return false; |
| | | } |
| | |
| | | using WIDESEA_Core; |
| | | using WIDESEAWCS_Common.TaskEnum; |
| | | using WIDESEAWCS_Core.LogHelper; |
| | | using WIDESEAWCS_ITaskInfoService; |
| | | using WIDESEAWCS_Model.Models; |
| | | using WIDESEAWCS_Tasks.Workflow.Abstractions; |
| | |
| | | namespace WIDESEAWCS_Tasks.Workflow |
| | | { |
| | | /// <summary> |
| | | /// RobotJob æµç¨ç¼æå¨ï¼è¿ç§»å RobotJob ç¶ææºåæ¯ï¼éä½ Job ç±»å¤æåº¦ã |
| | | /// æºå¨äººä»»å¡ç¼æå¨ - è´è´£ RobotJob ä¸çç¶ææºæµè½¬åæ§è¡æ¥éª¤ç¼æ |
| | | /// </summary> |
| | | /// <remarks> |
| | | /// è¿ç§»å RobotJob ç¶ææºæµè½¬æ¯æï¼éä½ Job å±çå¤æåº¦ã |
| | | /// |
| | | /// æ ¸å¿èè´£ï¼ |
| | | /// 1. æ ¹æ®æºå¨äººå½åç¶æåä»»å¡ç¶æï¼å³å®ä¸ä¸æ¥å¨ä½ |
| | | /// 2. å¤çåè´§å®æåçæ¾è´§æä»¤ä¸å |
| | | /// 3. å¤çæ¾è´§å®æåçåè´§æä»¤ä¸åï¼ç»çåºæ¯ï¼ |
| | | /// |
| | | /// ç¶ææºæµè½¬è§åï¼ |
| | | /// - æ¡ä»¶ï¼RobotRunMode == 2ï¼èªå¨æ¨¡å¼ï¼ä¸ RobotControlMode == 1ï¼å®¢æ·ç«¯æ§å¶ï¼ä¸ OperStatus != "Running" |
| | | /// - åè´§å®æ -> æ¾è´§ï¼PickFinished + RobotArmObject == 1 + RobotPickFinish -> åé Putbattery |
| | | /// - æ¾è´§å®æ -> åè´§ï¼PutFinished + Homed + RobotArmObject == 0 -> åé Pickbatteryï¼ç»ç/æ¢çåºæ¯ï¼ |
| | | /// </remarks> |
| | | public class RobotWorkflowOrchestrator : IRobotWorkflowOrchestrator |
| | | { |
| | | /// <summary> |
| | | /// æºæ¢°æç¶æç®¡çå¨ |
| | | /// </summary> |
| | | /// <remarks> |
| | | /// ç¨äºè¯»ååæ´æ°æºå¨äººçç¶æã |
| | | /// </remarks> |
| | | private readonly RobotStateManager _stateManager; |
| | | |
| | | /// <summary> |
| | | /// æºæ¢°æå®¢æ·ç«¯ç®¡çå¨ |
| | | /// </summary> |
| | | /// <remarks> |
| | | /// ç¨äºåæºå¨äººå®¢æ·ç«¯åéæä»¤ã |
| | | /// </remarks> |
| | | private readonly RobotClientManager _clientManager; |
| | | |
| | | /// <summary> |
| | | /// ä»»å¡å¤çå¨ |
| | | /// </summary> |
| | | /// <remarks> |
| | | /// ç¨äºæ§è¡ä»»å¡ç¸å
³çä¸å¡é»è¾ï¼å¦åéåè´§æä»¤ã |
| | | /// </remarks> |
| | | private readonly RobotTaskProcessor _taskProcessor; |
| | | |
| | | /// <summary> |
| | | /// æºå¨äººä»»å¡æå¡ |
| | | /// </summary> |
| | | /// <remarks> |
| | | /// ç¨äºæ´æ°ä»»å¡ç¶æã |
| | | /// </remarks> |
| | | private readonly IRobotTaskService _robotTaskService; |
| | | |
| | | /// <summary> |
| | | /// æé 彿° |
| | | /// </summary> |
| | | /// <param name="stateManager">ç¶æç®¡çå¨</param> |
| | | /// <param name="clientManager">客æ·ç«¯ç®¡çå¨</param> |
| | | /// <param name="taskProcessor">ä»»å¡å¤çå¨</param> |
| | | /// <param name="robotTaskService">任塿å¡</param> |
| | | public RobotWorkflowOrchestrator( |
| | | RobotStateManager stateManager, |
| | | RobotClientManager clientManager, |
| | |
| | | _robotTaskService = robotTaskService; |
| | | } |
| | | |
| | | /// <summary> |
| | | /// æ§è¡ä»»å¡ç¼ææµç¨ |
| | | /// </summary> |
| | | /// <remarks> |
| | | /// æ ¹æ®æºå¨äººå½åç¶æåä»»å¡ç¶æï¼å³å®æ¯å¦ä¸åæä»¤ã |
| | | /// |
| | | /// æ§è¡æ¡ä»¶ï¼ |
| | | /// 1. æºå¨äººå¤äºèªå¨æ¨¡å¼ï¼RobotRunMode == 2ï¼ |
| | | /// 2. æºå¨äººå¤äºå®¢æ·ç«¯æ§å¶æ¨¡å¼ï¼RobotControlMode == 1ï¼ |
| | | /// 3. æºå¨äººä¸å¨è¿è¡ä¸ï¼OperStatus != "Running"ï¼ |
| | | /// |
| | | /// æµè½¬é»è¾ï¼ |
| | | /// - åè´§å®æä¸æèæè´§ -> åéæ¾è´§æä»¤ï¼Putbatteryï¼ |
| | | /// - æ¾è´§å®æä¸æèæ è´§ -> åéåè´§æä»¤ï¼Pickbatteryï¼ |
| | | /// </remarks> |
| | | /// <param name="latestState">æºå¨äººææ°ç¶æ</param> |
| | | /// <param name="task">å¾
æ§è¡çæºå¨äººä»»å¡</param> |
| | | /// <param name="ipAddress">æºå¨äºº IP å°å</param> |
| | | public async Task ExecuteAsync(RobotSocketState latestState, Dt_RobotTask task, string ipAddress) |
| | | { |
| | | // ä¿æåæåæ¯å¤å®æ¡ä»¶ä¸åï¼ç¡®ä¿è¡ä¸ºä¸è´ã |
| | | // æåæ¹æ¡åæ¯å¤æï¼ç¡®ä¿é»è¾ä¸è´ |
| | | // æ£æ¥æ¯å¦æ»¡è¶³èªå¨æ§å¶æ¡ä»¶ï¼ |
| | | // 1. è¿è¡æ¨¡å¼ä¸ºèªå¨ï¼2ï¼ |
| | | // 2. æ§å¶æ¨¡å¼ä¸ºå®¢æ·ç«¯æ§å¶ï¼1ï¼ |
| | | // 3. è¿è¡ç¶æä¸æ¯ Runningï¼è¯´æå·²å®æå½åå¨ä½ï¼ |
| | | if (latestState.RobotRunMode == 2 && latestState.RobotControlMode == 1 && latestState.OperStatus != "Running") |
| | | { |
| | | // ========== åè´§å®æåçæ¾è´§å¤ç ========== |
| | | // æ¡ä»¶ï¼ |
| | | // - å½åå¨ä½æ¯ PickFinished æ AllPickFinishedï¼åè´§å®æï¼ |
| | | // - æèä¸æç©æï¼RobotArmObject == 1ï¼ |
| | | // - ä»»å¡ç¶æä¸º RobotPickFinishï¼å·²è®°å½åè´§å®æï¼ |
| | | if ((latestState.CurrentAction == "PickFinished" || latestState.CurrentAction == "AllPickFinished") |
| | | && latestState.RobotArmObject == 1 |
| | | && task.RobotTaskState == TaskRobotStatusEnum.RobotPickFinish.GetHashCode()) |
| | | { |
| | | // åéæ¾è´§æä»¤ |
| | | await HandlePickFinishedStateAsync(task, ipAddress); |
| | | } |
| | | // ========== æ¾è´§å®æåçåè´§å¤ç ========== |
| | | // æ¡ä»¶ï¼ |
| | | // - å½åå¨ä½æ¯ PutFinishedãAllPutFinished æ nullï¼æ¾è´§å®æï¼ |
| | | // - è¿è¡ç¶æä¸º Homedï¼å·²å½ä½ï¼ |
| | | // - æè䏿 ç©æï¼RobotArmObject == 0ï¼ |
| | | // - ä»»å¡ç¶æä¸º RobotPutFinish æä¸æ¯ RobotExecuting |
| | | else if ((latestState.CurrentAction == "PutFinished" || latestState.CurrentAction == "AllPutFinished" || latestState.CurrentAction == null) |
| | | && latestState.OperStatus == "Homed" |
| | | && latestState.RobotArmObject == 0 |
| | | && (task.RobotTaskState == TaskRobotStatusEnum.RobotPutFinish.GetHashCode() |
| | | || task.RobotTaskState != TaskRobotStatusEnum.RobotExecuting.GetHashCode())) |
| | | { |
| | | // åéåè´§æä»¤ |
| | | await HandlePutFinishedStateAsync(task, ipAddress); |
| | | } |
| | | } |
| | | } |
| | | |
| | | /// <summary> |
| | | /// å¤çåè´§å®æåçæ¾è´§æä»¤ |
| | | /// </summary> |
| | | /// <remarks> |
| | | /// å½åè´§å®æåï¼åæºå¨äººåéæ¾è´§æä»¤ï¼Putbatteryï¼ã |
| | | /// æºå¨äººæ¶å°æä»¤åä¼å°è´§ç©æ¾ç½®å°ç®æ å°åã |
| | | /// |
| | | /// æä»¤æ ¼å¼ï¼Putbattery,{ç®æ å°å} |
| | | /// ä¾å¦ï¼Putbattery,B01 表示å°è´§ç©æ¾ç½®å° B01 ä½ç½® |
| | | /// </remarks> |
| | | /// <param name="task">å½åä»»å¡</param> |
| | | /// <param name="ipAddress">æºå¨äºº IP å°å</param> |
| | | private async Task HandlePickFinishedStateAsync(Dt_RobotTask task, string ipAddress) |
| | | { |
| | | // æå»ºæ¾è´§æä»¤ï¼æ ¼å¼ï¼Putbattery,{ç®æ å°å} |
| | | string taskString = $"Putbattery,{task.RobotTargetAddress}"; |
| | | |
| | | // éè¿å®¢æ·ç«¯ç®¡çå¨åéæä»¤å°æºå¨äºº |
| | | bool result = await _clientManager.SendToClientAsync(ipAddress, taskString); |
| | | |
| | | if (result) |
| | | { |
| | | // åéæåï¼è®°å½æ¥å¿ |
| | | QuartzLogger.Error($"ä¸åæ¾è´§æä»¤ï¼æï¿½?: {taskString}", task.RobotRoadway); |
| | | |
| | | // æ´æ°ä»»å¡ç¶æä¸º"æºå¨äººæ§è¡ä¸" |
| | | task.RobotTaskState = TaskRobotStatusEnum.RobotExecuting.GetHashCode(); |
| | | |
| | | // è·åææ°ç¶æå¹¶æ´æ°ä»»å¡å
³è |
| | | var stateToUpdate = _stateManager.GetState(ipAddress); |
| | | if (stateToUpdate != null) |
| | | { |
| | | stateToUpdate.CurrentTask = task; |
| | | |
| | | // å®å
¨æ´æ°ç¶æå° Redis |
| | | if (_stateManager.TryUpdateStateSafely(ipAddress, stateToUpdate)) |
| | | { |
| | | // ç¶ææ´æ°æååï¼æ´æ°ä»»å¡è®°å½ |
| | | await _robotTaskService.UpdateRobotTaskAsync(task); |
| | | } |
| | | } |
| | | } |
| | | } |
| | | |
| | | /// <summary> |
| | | /// å¤çæ¾è´§å®æåçåè´§æä»¤ |
| | | /// </summary> |
| | | /// <remarks> |
| | | /// 彿¾è´§å®æåï¼æ ¹æ®ä»»å¡ç±»åå³å®ä¸ä¸æ¥ï¼ |
| | | /// |
| | | /// 1. 妿䏿¯æçä¹ä¸æ¯ç»çï¼æ®éä»»å¡ï¼ï¼ |
| | | /// - ç´æ¥åéåè´§æä»¤ |
| | | /// |
| | | /// 2. 妿æ¯ç»çææ¢çä»»å¡ï¼ |
| | | /// - çææ°çæçæ¡ç |
| | | /// - å°æ¡ç æ·»å å°ç¶æä¸ |
| | | /// - åéåè´§æä»¤ |
| | | /// |
| | | /// ç»çä»»å¡çæ¡ç ç¨äºæ è¯æ°çæçæçï¼ |
| | | /// åç»æ¾è´§æ¶ä¼ç¨å°è¿äºæ¡ç ä¿¡æ¯ã |
| | | /// </remarks> |
| | | /// <param name="task">å½åä»»å¡</param> |
| | | /// <param name="ipAddress">æºå¨äºº IP å°å</param> |
| | | private async Task HandlePutFinishedStateAsync(Dt_RobotTask task, string ipAddress) |
| | | { |
| | | // è·åææ°ç¶æ |
| | | var stateForUpdate = _stateManager.GetState(ipAddress); |
| | | if (stateForUpdate == null) |
| | | { |
| | | return; |
| | | } |
| | | |
| | | // å¦æç¶æä¸è¿æ²¡æè®¾ç½®ä»»å¡ç±»åæ å¿ï¼æ ¹æ®ä»»å¡ç±»å设置 |
| | | if (!stateForUpdate.IsSplitPallet && !stateForUpdate.IsGroupPallet) |
| | | { |
| | | // 夿任å¡ç±»å并设置ç¸åºçæ å¿ |
| | | stateForUpdate.IsSplitPallet = task.RobotTaskType == RobotTaskTypeEnum.SplitPallet.GetHashCode(); |
| | | stateForUpdate.IsGroupPallet = task.RobotTaskType == RobotTaskTypeEnum.GroupPallet.GetHashCode() |
| | | || task.RobotTaskType == RobotTaskTypeEnum.ChangePallet.GetHashCode(); |
| | | } |
| | | |
| | | // 妿æ¯ç»çä»»å¡ï¼å
æ¬æ¢çï¼ |
| | | if (task.RobotTaskType == RobotTaskTypeEnum.GroupPallet.GetHashCode()) |
| | | { |
| | | // çææçæ¡ç åç¼ |
| | | const string prefix = "TRAY"; |
| | | |
| | | // çæä¸¤ä¸ªæçæ¡ç ï¼ç¨äºç»çæä½ï¼ |
| | | string trayBarcode1 = RobotBarcodeGenerator.GenerateTrayBarcode(prefix); |
| | | string trayBarcode2 = RobotBarcodeGenerator.GenerateTrayBarcode(prefix); |
| | | |
| | | // 妿æ¡ç çææå |
| | | if (!string.IsNullOrEmpty(trayBarcode1) && !string.IsNullOrEmpty(trayBarcode2)) |
| | | { |
| | | // å°æ¡ç æ·»å å°ç¶æä¸ï¼ä¾åç»æ¾è´§æ¶ä½¿ç¨ |
| | | stateForUpdate.CellBarcode.Add(trayBarcode1); |
| | | stateForUpdate.CellBarcode.Add(trayBarcode2); |
| | | |
| | | // è®°å½æ¥å¿ |
| | | QuartzLogger.Error($"ȡ�������о�ţ���о: {trayBarcode1}+{trayBarcode2}", stateForUpdate.RobotCrane.DeviceName); |
| | | |
| | | // åéåè´§æä»¤ |
| | | await _taskProcessor.SendSocketRobotPickAsync(task, stateForUpdate); |
| | | } |
| | | } |
| | | else |
| | | { |
| | | // éç»çä»»å¡ï¼ç´æ¥åéåè´§æä»¤ |
| | | await _taskProcessor.SendSocketRobotPickAsync(task, stateForUpdate); |
| | | } |
| | | } |
| | | } |
| | | } |
| | | |
| | | |
| | |
| | | namespace WIDESEAWCS_Tasks.SocketServer |
| | | { |
| | | /// <summary> |
| | | /// TcpSocketServer çéé
å¨å®ç°ï¼ä¿æåºå±è¡ä¸ºä¸åï¼ä»
åè®¿é®æ¶å£ã |
| | | /// TcpSocketServer çç½å
³å®ç° |
| | | /// </summary> |
| | | /// <remarks> |
| | | /// å®ç° ISocketClientGateway æ¥å£ï¼å°åºå± TCP éä¿¡ç»èå°è£
ã |
| | | /// 使ä¸å¡å±ä¸ç´æ¥ä¾èµ TcpSocketServerï¼ä¾¿äºåå
æµè¯åæ¿æ¢å®ç°ã |
| | | /// </remarks> |
| | | public class SocketClientGateway : ISocketClientGateway |
| | | { |
| | | /// <summary> |
| | | /// TCP Socket æå¡å¨å®ä¾ |
| | | /// </summary> |
| | | private readonly TcpSocketServer _tcpSocket; |
| | | |
| | | /// <summary> |
| | | /// æé 彿° |
| | | /// </summary> |
| | | /// <param name="tcpSocket">TCP Socket æå¡å¨å®ä¾</param> |
| | | public SocketClientGateway(TcpSocketServer tcpSocket) |
| | | { |
| | | _tcpSocket = tcpSocket; |
| | | } |
| | | |
| | | /// <summary> |
| | | /// 弿¥åéæ¶æ¯å°æå®å®¢æ·ç«¯ |
| | | /// </summary> |
| | | /// <param name="clientId">ç®æ 客æ·ç«¯ ID</param> |
| | | /// <param name="message">æ¶æ¯å
容</param> |
| | | /// <returns>å鿝妿å</returns> |
| | | public Task<bool> SendToClientAsync(string clientId, string message) |
| | | { |
| | | return _tcpSocket.SendToClientAsync(clientId, message); |
| | | } |
| | | |
| | | /// <summary> |
| | | /// éè¿ TcpClient åéæ¶æ¯ |
| | | /// </summary> |
| | | /// <param name="client">TCP 客æ·ç«¯è¿æ¥</param> |
| | | /// <param name="message">æ¶æ¯å
容</param> |
| | | public Task SendMessageAsync(TcpClient client, string message) |
| | | { |
| | | return _tcpSocket.SendMessageAsync(client, message); |
| | | } |
| | | |
| | | /// <summary> |
| | | /// è·åææå·²è¿æ¥å®¢æ·ç«¯ ID |
| | | /// </summary> |
| | | /// <returns>客æ·ç«¯ ID å表</returns> |
| | | public IReadOnlyList<string> GetClientIds() |
| | | { |
| | | return _tcpSocket.GetClientIds(); |
| | | } |
| | | |
| | | /// <summary> |
| | | /// å¤ç客æ·ç«¯è¿æ¥çæ¶æ¯å¾ªç¯ |
| | | /// </summary> |
| | | /// <param name="client">TCP 客æ·ç«¯è¿æ¥</param> |
| | | /// <param name="clientId">客æ·ç«¯ ID</param> |
| | | /// <param name="cancellationToken">忶令ç</param> |
| | | /// <param name="robotCrane">æºå¨äººç¶æ</param> |
| | | /// <returns>ä»»å¡</returns> |
| | | public Task HandleClientAsync(TcpClient client, string clientId, CancellationToken cancellationToken, RobotSocketState robotCrane) |
| | | { |
| | | return _tcpSocket.HandleClientAsync(client, clientId, cancellationToken, robotCrane); |
| | | } |
| | | } |
| | | } |
| | | |
| | |
| | | namespace WIDESEAWCS_Tasks.SocketServer |
| | | { |
| | | /// <summary> |
| | | /// Socketæå¡ç«¯æç®¡æå¡ |
| | | /// Socket æå¡å¨åå°ä¸»æºæå¡ |
| | | /// </summary> |
| | | /// <remarks> |
| | | /// å®ç° IHostedService æ¥å£ï¼ä½ä¸º ASP.NET Core çåå°æå¡è¿è¡ã |
| | | /// è´è´£å¨åºç¨å¯å¨æ¶å¯å¨ Socket æå¡å¨ï¼åæ¢æ¶å
³éæå¡å¨ã |
| | | /// </remarks> |
| | | public class SocketServerHostedService : IHostedService |
| | | { |
| | | /// <summary> |
| | | /// TCP Socket æå¡å¨å®ä¾ |
| | | /// </summary> |
| | | private readonly TcpSocketServer _server; |
| | | |
| | | /// <summary> |
| | | /// Socket æå¡å¨é
ç½®é项 |
| | | /// </summary> |
| | | private readonly SocketServerOptions _options; |
| | | |
| | | /// <summary> |
| | | /// æé 彿° |
| | | /// </summary> |
| | | /// <param name="server">TCP Socket æå¡å¨å®ä¾</param> |
| | | /// <param name="options">é
ç½®é项</param> |
| | | public SocketServerHostedService(TcpSocketServer server, IOptions<SocketServerOptions> options) |
| | | { |
| | | _server = server; |
| | | _options = options.Value; |
| | | } |
| | | |
| | | /// <summary> |
| | | /// å¯å¨ Socket æå¡å¨ |
| | | /// </summary> |
| | | /// <remarks> |
| | | /// 妿é
ç½®ä¸æå¡å¨è¢«ç¦ç¨ï¼Enabled=falseï¼ï¼åä¸å¯å¨ã |
| | | /// </remarks> |
| | | /// <param name="cancellationToken">忶令ç</param> |
| | | /// <returns>å¯å¨ä»»å¡</returns> |
| | | public Task StartAsync(CancellationToken cancellationToken) |
| | | { |
| | | // æ£æ¥æå¡å¨æ¯å¦å¯ç¨ |
| | | if (!_options.Enabled) |
| | | { |
| | | return Task.CompletedTask; |
| | | } |
| | | |
| | | // å¯å¨æå¡å¨ |
| | | return _server.StartAsync(cancellationToken); |
| | | } |
| | | |
| | | /// <summary> |
| | | /// 忢 Socket æå¡å¨ |
| | | /// </summary> |
| | | /// <param name="cancellationToken">忶令ç</param> |
| | | /// <returns>忢任å¡</returns> |
| | | public Task StopAsync(CancellationToken cancellationToken) |
| | | { |
| | | return _server.StopAsync(cancellationToken); |
| | |
| | | namespace WIDESEAWCS_Tasks.SocketServer |
| | | { |
| | | /// <summary> |
| | | /// Socketæå¡ç«¯é
ç½® |
| | | /// Socket æå¡å¨é
ç½®é项 |
| | | /// </summary> |
| | | /// <remarks> |
| | | /// ç¨äºé
ç½® TCP Socket æå¡å¨çè¿è¡åæ°ã |
| | | /// é
ç½®éè¿ appsettings.json ç SocketServer èç¹å è½½ã |
| | | /// </remarks> |
| | | public class SocketServerOptions : IConfigurableOptions |
| | | { |
| | | /// <summary> |
| | | /// æ¯å¦å¯ç¨ |
| | | /// æ¯å¦å¯ç¨ Socket æå¡å¨ |
| | | /// </summary> |
| | | /// <remarks> |
| | | /// 设置为 false æ¶ï¼æå¡å¨ä¸ä¼å¯å¨ã |
| | | /// </remarks> |
| | | public bool Enabled { get; set; } = true; |
| | | |
| | | /// <summary> |
| | | /// çå¬ç«¯å£ |
| | | /// æå¡å¨çå¬ç«¯å£ |
| | | /// </summary> |
| | | /// <remarks> |
| | | /// TCP 客æ·ç«¯è¿æ¥å°æ¤ç«¯å£ã |
| | | /// é»è®¤ä¸º 2000ã |
| | | /// </remarks> |
| | | public int Port { get; set; } = 2000; |
| | | |
| | | /// <summary> |
| | | /// çå¬å°å |
| | | /// çå¬å°å |
| | | /// </summary> |
| | | /// <remarks> |
| | | /// æå¡å¨ç»å®å°æ¤å°åã |
| | | /// 0.0.0.0 表示ç嬿æç½ç»æ¥å£ã |
| | | /// </remarks> |
| | | public string IpAddress { get; set; } = "0.0.0.0"; |
| | | |
| | | /// <summary> |
| | | /// è¿æ¥éåé¿åº¦ |
| | | /// è¿æ¥éåé¿åº¦ |
| | | /// </summary> |
| | | /// <remarks> |
| | | /// çå¾
æ¥åçè¿æ¥éåæå¤§é¿åº¦ã |
| | | /// </remarks> |
| | | public int Backlog { get; set; } = 1000; |
| | | |
| | | /// <summary> |
| | | /// ææ¬ç¼ç åç§°ï¼ä¾å¦: utf-8, gbkï¼ |
| | | /// å符ç¼ç åç§° |
| | | /// </summary> |
| | | /// <remarks> |
| | | /// ç¨äºæ¶æ¯çå符ç¼ç ï¼å¦ utf-8ãgbkã |
| | | /// </remarks> |
| | | public string EncodingName { get; set; } = "utf-8"; |
| | | |
| | | /// <summary> |
| | | /// æ¯å¦èªå¨æ£æµç¼ç ï¼å°è¯ UTF-8 ååéå° GBKï¼ |
| | | /// æ¯å¦èªå¨æ£æµç¼ç ï¼é对 GBK 客æ·ç«¯ï¼ |
| | | /// </summary> |
| | | /// <remarks> |
| | | /// å½è®¾ç½®ä¸º true æ¶ï¼ä¼èªå¨æ£æµå®¢æ·ç«¯æ¶æ¯çç¼ç ã |
| | | /// å¦ææ¶æ¯æ¯ UTF-8 æ ¼å¼åç¨ UTF-8 è§£ç ï¼å¦åå°è¯ GBK è§£ç ã |
| | | /// </remarks> |
| | | public bool AutoDetectEncoding { get; set; } = true; |
| | | |
| | | /// <summary> |
| | | /// 客æ·ç«¯ç©ºé²è¶
æ¶æ¶é´ï¼ç§ï¼ï¼è¶
è¿åæå¼ |
| | | /// 客æ·ç«¯ç©ºé²è¶
æ¶æ¶é´ï¼ç§ï¼ |
| | | /// </summary> |
| | | /// <remarks> |
| | | /// 妿客æ·ç«¯å¨æ¤æ¶é´å
æ²¡ææ´»å¨ï¼æå¼è¿æ¥ã |
| | | /// 设置为 0 表示ä¸å¯ç¨è¶
æ¶ã |
| | | /// </remarks> |
| | | public int IdleTimeoutSeconds { get; set; } = 300; |
| | | |
| | | /// <summary> |
| | | /// æ¯å¦å¯ç¨å¿è·³æ£æ¥ |
| | | /// æ¯å¦å¯ç¨å¿è·³æ£æµ |
| | | /// </summary> |
| | | /// <remarks> |
| | | /// å¯ç¨åï¼ä¼å¨è¿æ¥ç©ºé²æ¶åéå¿è·³æ¢æµã |
| | | /// </remarks> |
| | | public bool EnableHeartbeat { get; set; } = true; |
| | | |
| | | /// <summary> |
| | | /// æ¥å¿æä»¶è·¯å¾ï¼ç¸å¯¹äºç¨åºè¿è¡ç®å½ï¼ |
| | | /// æ¥å¿æä»¶è·¯å¾ |
| | | /// </summary> |
| | | /// <remarks> |
| | | /// æ¥å¿æä»¶çç¸å¯¹è·¯å¾ï¼ç¸å¯¹äºåºç¨ç¨åºç®å½ã |
| | | /// </remarks> |
| | | public string LogFilePath { get; set; } = "socketserver.log"; |
| | | |
| | | /// <summary> |
| | | /// æ¶æ¯å¤´æ è®° |
| | | /// æ¶æ¯å¤´æ è¯ |
| | | /// </summary> |
| | | /// <remarks> |
| | | /// ç¨äºå¸§è§£æçæ¶æ¯å¤´ã |
| | | /// æ¥æ¶æ¶æ¯æ¶æ¥æ¾æ¤å¤´æ è¯ã |
| | | /// </remarks> |
| | | public string MessageHeader { get; set; } = "<START>"; |
| | | |
| | | /// <summary> |
| | | /// æ¶æ¯å°¾æ è®° |
| | | /// æ¶æ¯å°¾æ è¯ |
| | | /// </summary> |
| | | /// <remarks> |
| | | /// ç¨äºå¸§è§£æçæ¶æ¯å°¾ã |
| | | /// æ¥æ¶æ¶æ¯æ¶æ¥æ¾æ¤å°¾æ è¯ã |
| | | /// </remarks> |
| | | public string MessageFooter { get; set; } = "<END>"; |
| | | } |
| | | } |
| | |
| | | public partial class TcpSocketServer |
| | | { |
| | | /// <summary> |
| | | /// æ£ç´¢å½å卿å¡ä¸æ³¨åçææå®¢æ·ç«¯æ è¯ç¬¦çåªè¯»å表ã |
| | | /// è·åææå·²è¿æ¥å®¢æ·ç«¯ ID å表 |
| | | /// </summary> |
| | | /// <remarks>è¿åçå表表示è°ç¨æ¶å»å®¢æ·ç«¯IDçå¿«ç
§ãåç»å¯¹å®¢æ·ç«¯éåçæ´æ¹ä¸ä¼å½±åè¿åçåè¡¨ãæ¤æ¹æ³æ¯çº¿ç¨å®å
¨çã</remarks> |
| | | /// <returns>å
å«å®¢æ·ç«¯IDç<see cref="IReadOnlyList{String}"/>ãå¦ææ²¡æå®¢æ·ç«¯æ³¨åï¼å表å°ä¸ºç©ºã</returns> |
| | | /// <remarks> |
| | | /// è¿åå½å卿å¡å¨æ³¨åç客æ·ç«¯æ è¯å表ã |
| | | /// è¿æ¯ä¸ä¸ªåªè¯»å表çå¿«ç
§ï¼çº¿ç¨å®å
¨ã |
| | | /// </remarks> |
| | | /// <returns>客æ·ç«¯ ID å表</returns> |
| | | public IReadOnlyList<string> GetClientIds() |
| | | { |
| | | lock (_syncRoot) |
| | |
| | | } |
| | | |
| | | /// <summary> |
| | | /// æ£ç´¢ä¸æå®è®¾å¤æ è¯ç¬¦å
³èç客æ·ç«¯æ è¯ç¬¦ã |
| | | /// æ ¹æ®è®¾å¤ ID è·å客æ·ç«¯ ID |
| | | /// </summary> |
| | | /// <remarks>æ¤æ¹æ³æ¯çº¿ç¨å®å
¨çãå¦ææªæ¾å°è®¾å¤æ è¯ç¬¦ï¼æ¹æ³å°è¿ånullè䏿¯æåºå¼å¸¸ã</remarks> |
| | | /// <param name="deviceId">è¦æ£ç´¢å®¢æ·ç«¯æ è¯ç¬¦ç设å¤çå¯ä¸æ è¯ç¬¦ãä¸è½ä¸ºnullã</param> |
| | | /// <returns>䏿å®è®¾å¤æ è¯ç¬¦å
³èç客æ·ç«¯æ è¯ç¬¦ï¼å¦æä¸åå¨å
³èåè¿ånullã</returns> |
| | | /// <remarks> |
| | | /// å¨è®¾å¤ç»å®è¡¨ä¸æ¥æ¾å¯¹åºç客æ·ç«¯ IDã |
| | | /// </remarks> |
| | | /// <param name="deviceId">设å¤å¯ä¸æ è¯</param> |
| | | /// <returns>客æ·ç«¯ IDï¼å¦ææªæ¾å°åè¿å null</returns> |
| | | public string? GetClientIdByDevice(string deviceId) |
| | | { |
| | | lock (_syncRoot) |
| | |
| | | } |
| | | |
| | | /// <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> |
| | | /// <remarks> |
| | | /// éè¿è®¾å¤ ID æ¥æ¾å¯¹åºç客æ·ç«¯è¿æ¥ï¼ç¶ååéæ¶æ¯ã |
| | | /// å¦æè®¾å¤æªæ³¨åæè¿æ¥ä¸åå¨ï¼è¿å falseã |
| | | /// </remarks> |
| | | /// <param name="deviceId">ç®æ 设å¤å¯ä¸æ è¯</param> |
| | | /// <param name="message">è¦åéçæ¶æ¯</param> |
| | | /// <returns>å鿝妿å</returns> |
| | | public Task<bool> SendToDeviceAsync(string deviceId, string message) |
| | | { |
| | | var clientId = GetClientIdByDevice(deviceId); |
| | |
| | | } |
| | | |
| | | /// <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> |
| | | /// <remarks> |
| | | /// 使ç¨å¸§æ ¼å¼åéæ¶æ¯ï¼æ·»å 头尾æ è¯ï¼ã |
| | | /// æ¯ä¸ªå®¢æ·ç«¯çåéæä½æ¯äºæ¥çï¼éè¿ä¿¡å·éå®ç°ï¼ã |
| | | /// 妿客æ·ç«¯æªè¿æ¥æä¸åå¨ï¼åé失败è¿å falseã |
| | | /// </remarks> |
| | | /// <param name="clientId">ç®æ 客æ·ç«¯ ID</param> |
| | | /// <param name="message">è¦åéçæ¶æ¯</param> |
| | | /// <returns>å鿝妿å</returns> |
| | | public async Task<bool> SendToClientAsync(string clientId, string message) |
| | | { |
| | | TcpClient? client; |
| | |
| | | |
| | | enc ??= _textEncoding; |
| | | |
| | | // è·å客æ·ç«¯åéé |
| | | if (sem != null) await sem.WaitAsync(); |
| | | try |
| | | { |
| | | // åéæ¶æ¯ |
| | | var ns = client.GetStream(); |
| | | var framedMessage = BuildFramedMessage(message); |
| | | var data = enc.GetBytes(framedMessage); |
| | |
| | | } |
| | | |
| | | /// <summary> |
| | | /// 弿¥åææå·²è¿æ¥ç客æ·ç«¯åéæå®çæ¶æ¯ã |
| | | /// 弿¥å¹¿ææ¶æ¯å°ææå®¢æ·ç«¯ |
| | | /// </summary> |
| | | /// <remarks>妿åæä¸ªå®¢æ·ç«¯åéæ¶æ¯æ¶åçé误ï¼å¼å¸¸å°è¢«æå¶å¹¶ç»§ç»åå
¶ä»å®¢æ·ç«¯å¹¿æã |
| | | /// 彿æåéæä½å®æåï¼æ¤æ¹æ³ç»æã</remarks> |
| | | /// <param name="message">è¦å¹¿æç»ææå®¢æ·ç«¯çæ¶æ¯ãä¸è½ä¸ºnullã</param> |
| | | /// <returns>è¡¨ç¤ºå¼æ¥å¹¿ææä½çä»»å¡ã</returns> |
| | | /// <remarks> |
| | | /// å°æ¶æ¯åéç»ææå·²è¿æ¥ç客æ·ç«¯ã |
| | | /// 妿æä¸ªå®¢æ·ç«¯åé失败ï¼ä¸å½±åå
¶ä»å®¢æ·ç«¯çåéã |
| | | /// </remarks> |
| | | /// <param name="message">è¦å¹¿æçæ¶æ¯</param> |
| | | public async Task BroadcastAsync(string message) |
| | | { |
| | | List<TcpClient> clients; |
| | |
| | | clients = _clients.Values.ToList(); |
| | | } |
| | | |
| | | // å¹¶è¡åéæ¶æ¯å°ææå®¢æ·ç«¯ |
| | | await Task.WhenAll(clients.Select(c => Task.Run(async () => |
| | | { |
| | | try { await SendMessageAsync(c, message); } catch { } |
| | |
| | | } |
| | | |
| | | /// <summary> |
| | | /// éè¿ç½ç»æµå¼æ¥åæå®çTCP客æ·ç«¯åéå¸¦å¸§çææ¬æ¶æ¯ã |
| | | /// éè¿ NetworkStream åéæ¶æ¯ |
| | | /// </summary> |
| | | /// <remarks>妿客æ·ç«¯ä¸ºnullææªè¿æ¥ï¼æ¤æ¹æ³å°ç«å³è¿åèä¸åéæ¶æ¯ã |
| | | /// æ¶æ¯å°ä½¿ç¨é
ç½®çææ¬ç¼ç è¿è¡ç¼ç å¹¶æ·»å 帧头åéè¿ç½ç»æµåéã</remarks> |
| | | /// <param name="client">è¦åéæ¶æ¯å°çTCP客æ·ç«¯ãå¿
é¡»å¤äºè¿æ¥ç¶æï¼å¦åæ¹æ³ä¸æ§è¡ä»»ä½æä½ã</param> |
| | | /// <param name="message">è¦åéç»å®¢æ·ç«¯çææ¬æ¶æ¯ãæ¶æ¯å¨ä¼ è¾åå°è¢«ç¼ç å¹¶æ·»å 帧头ã</param> |
| | | /// <returns>è¡¨ç¤ºå¼æ¥åéæä½çä»»å¡ã</returns> |
| | | /// <remarks> |
| | | /// ç´æ¥ä½¿ç¨ TcpClient ç NetworkStream åéæ¶æ¯ã |
| | | /// æ¶æ¯ä¼æ·»å 帧头帧尾ã |
| | | /// </remarks> |
| | | /// <param name="client">TCP 客æ·ç«¯</param> |
| | | /// <param name="message">æ¶æ¯å
容</param> |
| | | public async Task SendMessageAsync(TcpClient client, string message) |
| | | { |
| | | if (client == null || !client.Connected) |
| | |
| | | public partial class TcpSocketServer |
| | | { |
| | | /// <summary> |
| | | /// éæ¾æå¡å¨ä½¿ç¨çææèµæºå¹¶åæ¢çå¬ä¼ å
¥è¿æ¥ã |
| | | /// éæ¾æå¡å¨èµæº |
| | | /// </summary> |
| | | /// <remarks>å½ä¸åéè¦æå¡å¨æ¶è°ç¨æ¤æ¹æ³ï¼ä»¥ç¡®ä¿ææç¸å
³èµæºï¼å¦ç½ç»çå¬å¨å忥åè¯ï¼è¢«æ£ç¡®éæ¾ã |
| | | /// è°ç¨ <see cref="Dispose"/> åï¼æå¡å¨æ æ³éæ°å¯å¨æå次使ç¨ã</remarks> |
| | | /// <remarks> |
| | | /// 忢çå¬ãåæ¶ææå®¢æ·ç«¯ä»»å¡ãå
³éçå¬å¨ãéæ¾ä¿¡å·éã |
| | | /// è°ç¨æ¤æ¹æ³åï¼æå¡å¨æ æ³å次使ç¨ã |
| | | /// </remarks> |
| | | public void Dispose() |
| | | { |
| | | // åæ¶æææä½ |
| | | _cts?.Cancel(); |
| | | |
| | | // 忢çå¬å¨ |
| | | _listener?.Stop(); |
| | | |
| | | // éæ¾åæ¶ä»¤çæº |
| | | _cts?.Dispose(); |
| | | |
| | | // éæ¾ææå®¢æ·ç«¯ä¿¡å·é |
| | | foreach (var sem in _clientLocks.Values) { try { sem.Dispose(); } catch { } } |
| | | _clientLocks.Clear(); |
| | | |
| | | // è®°å½åæ¢æ¥å¿ |
| | | Log($"[{DateTime.Now}] TcpSocketServer stopped"); |
| | | } |
| | | } |
| | |
| | | public partial class TcpSocketServer |
| | | { |
| | | /// <summary> |
| | | /// 弿¥å¤çä¸å·²è¿æ¥çTCP客æ·ç«¯çéä¿¡ï¼å¤çæºå¨äººèµ·éæºä¼è¯ä¸çä¼ å
¥æ¶æ¯å客æ·ç«¯ç¶ææ´æ°ã |
| | | /// å¤ç客æ·ç«¯è¿æ¥çæ¶æ¯å¾ªç¯ |
| | | /// </summary> |
| | | /// <remarks>æ¤æ¹æ³ç®¡ç客æ·ç«¯è¿æ¥ççå½å¨æï¼å
æ¬è¯»åæ¶æ¯ãæ´æ°å®¢æ·ç«¯ç¶æåè°ç¨ç¸å
³äºä»¶ã |
| | | /// å½å¤çç»ææ¶ï¼å®¢æ·ç«¯åç¸å
³çç½ç»èµæºå°è¢«éæ¾ã妿å¯ç¨å¿è·³æç©ºé²è¶
æ¶éé¡¹ï¼ |
| | | /// å°åºç¨é¢å¤çåæ¶é»è¾ãäºä»¶è°ç¨æé´çå¼å¸¸å°è¢«æè·å¹¶æå¶ï¼ä»¥ç¡®ä¿ä¼è¯å¤çç鲿£æ§ã</remarks> |
| | | /// <param name="client">表示è¦å¤ççè¿ç¨è¿æ¥çTCP客æ·ç«¯ãæ¹æ³å®æåå°éæ¾æ¤å¯¹è±¡ã</param> |
| | | /// <param name="clientId">å·²è¿æ¥å®¢æ·ç«¯çå¯ä¸æ è¯ç¬¦ãç¨äºå¨æ´ä¸ªä¼è¯ä¸è·è¸ªåæ´æ°å®¢æ·ç«¯ç¶æã</param> |
| | | /// <param name="cancellationToken">å¯ç¨äºåæ¶å®¢æ·ç«¯å¤çæä½ç忶令çãå¦æè¯·æ±åæ¶ï¼æ¹æ³å°ç«å³ç»æ¢å¤çã</param> |
| | | /// <param name="robotCrane">表示ä¸å®¢æ·ç«¯å
³èçæºå¨äººèµ·éæºçå½åç¶æå¯¹è±¡ãç¨äºä¸ºæ¶æ¯å¤çåäºä»¶è°ç¨æä¾ä¸ä¸æã</param> |
| | | /// <returns>表示å¤ç客æ·ç«¯è¿æ¥ç弿¥æä½çä»»å¡ãå½å®¢æ·ç«¯æå¼è¿æ¥æè¯·æ±åæ¶æ¶ä»»å¡å®æã</returns> |
| | | /// <remarks> |
| | | /// æç»æ¥æ¶å®¢æ·ç«¯æ¶æ¯ï¼ç´å°è¿æ¥æå¼æåæ¶ã |
| | | /// å¤çæµç¨ï¼ |
| | | /// 1. æ¥æ¶æ¶æ¯ï¼å¸§è§£æï¼ |
| | | /// 2. æ´æ°å®¢æ·ç«¯ç¶æï¼æ´»è·æ¶é´ãç¼ç ï¼ |
| | | /// 3. å¤çè®¾å¤æ³¨å |
| | | /// 4. 触å MessageReceived äºä»¶ |
| | | /// è¿æ¥æå¼æ¶æ¸
çèµæºå¹¶è§¦å RobotReceived äºä»¶ã |
| | | /// </remarks> |
| | | /// <param name="client">TCP 客æ·ç«¯è¿æ¥</param> |
| | | /// <param name="clientId">客æ·ç«¯å¯ä¸æ è¯</param> |
| | | /// <param name="cancellationToken">忶令ç</param> |
| | | /// <param name="robotCrane">æºå¨äººç¶æ</param> |
| | | public async Task HandleClientAsync(TcpClient client, string clientId, CancellationToken cancellationToken, RobotSocketState robotCrane) |
| | | { |
| | | using (client) |
| | |
| | | CancellationTokenSource? localCts = null; |
| | | if (_options.EnableHeartbeat || _options.IdleTimeoutSeconds > 0) |
| | | { |
| | | // åå»ºé¾æ¥çåæ¶ä»¤çæº |
| | | localCts = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken); |
| | | } |
| | | |
| | | try |
| | | { |
| | | // æ¶æ¯æ¥æ¶å¾ªç¯ |
| | | while (!cancellationToken.IsCancellationRequested && client.Connected) |
| | | { |
| | | string? message; |
| | | try |
| | | { |
| | | var ct = localCts?.Token ?? cancellationToken; |
| | | // æ¥æ¶å®æ´æ¶æ¯ï¼å¸§è§£æï¼ |
| | | message = await ReceiveFullMessageAsync(networkStream, _textEncoding, ct); |
| | | //message = await reader.ReadLineAsync().WaitAsync(ct); |
| | | } |
| | | catch (OperationCanceledException) |
| | | { |
| | |
| | | break; |
| | | } |
| | | |
| | | // æ´æ°å®¢æ·ç«¯ç¶æ |
| | | UpdateClientStatus(clientId, message); |
| | | |
| | | string messageLower = message.ToLowerInvariant(); |
| | | |
| | | // å¤çæ³¨åæ¶æ¯ |
| | | if (TryHandleRegister(messageLower, message, clientId, networkStream, cancellationToken)) |
| | | { |
| | | continue; |
| | | } |
| | | |
| | | // è§¦åæ¶æ¯æ¥æ¶äºä»¶ |
| | | if (MessageReceived != null) |
| | | { |
| | | try |
| | | { |
| | | // 夿æ¯å¦ä¸º JSON æ ¼å¼ |
| | | // 夿æ¯å¦ä¸º JSON æ ¼å¼ |
| | | bool isJsonFormat = TryParseJsonSilent(message); |
| | | _ = MessageReceived.Invoke(message, isJsonFormat, client, robotCrane); |
| | | } |
| | |
| | | } |
| | | finally |
| | | { |
| | | // æ¸
çèµæº |
| | | try { localCts?.Cancel(); localCts?.Dispose(); } catch { } |
| | | RemoveClient(clientId); |
| | | try { _ = RobotReceived.Invoke(clientId); } catch { } |
| | |
| | | } |
| | | |
| | | /// <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> |
| | | /// <remarks> |
| | | /// æ³¨åæ¶æ¯æ ¼å¼ï¼register,{deviceId} |
| | | /// å°è®¾å¤ ID ç»å®å°å½å客æ·ç«¯ IDã |
| | | /// </remarks> |
| | | /// <param name="messageLower">æ¶æ¯å°åçæ¬</param> |
| | | /// <param name="message">åå§æ¶æ¯</param> |
| | | /// <param name="clientId">客æ·ç«¯ ID</param> |
| | | /// <param name="networkStream">ç½ç»æµ</param> |
| | | /// <param name="cancellationToken">忶令ç</param> |
| | | /// <returns>æ¯å¦å¤çäºæ³¨åæ¶æ¯</returns> |
| | | private bool TryHandleRegister(string messageLower, string message, string clientId, NetworkStream networkStream, CancellationToken cancellationToken) |
| | | { |
| | | if (!messageLower.StartsWith("register,")) |
| | |
| | | return false; |
| | | } |
| | | |
| | | // æåè®¾å¤ ID |
| | | string deviceId = message.Substring("register,".Length).Trim(); |
| | | if (!string.IsNullOrEmpty(deviceId)) |
| | | { |
| | | lock (_syncRoot) |
| | | { |
| | | // ç»å®è®¾å¤å°å®¢æ·ç«¯ |
| | | _deviceBindings[deviceId] = clientId; |
| | | } |
| | | |
| | | // å夿³¨åæå |
| | | _ = WriteToClientAsync(clientId, networkStream, $"Registered,{deviceId}", cancellationToken); |
| | | } |
| | | |
| | |
| | | } |
| | | |
| | | /// <summary> |
| | | /// æ´æ°å®¢æ·ç«¯ç¶æ |
| | | /// æ´æ°å®¢æ·ç«¯ç¶æ |
| | | /// </summary> |
| | | /// <param name="clientId"></param> |
| | | /// <param name="message"></param> |
| | | /// <remarks> |
| | | /// æ´æ°æåæ´»è·æ¶é´åå符ç¼ç ã |
| | | /// 妿å¼å¯äºèªå¨ç¼ç æ£æµï¼æ ¹æ®æ¶æ¯å
å®¹å¤ææ¯ UTF-8 è¿æ¯ GBKã |
| | | /// </remarks> |
| | | /// <param name="clientId">客æ·ç«¯ ID</param> |
| | | /// <param name="message">ææ°æ¥æ¶çæ¶æ¯</param> |
| | | private void UpdateClientStatus(string clientId, string message) |
| | | { |
| | | lock (_syncRoot) |
| | | { |
| | | // æ´æ°æåæ´»è·æ¶é´ |
| | | _clientLastActive[clientId] = DateTime.Now; |
| | | |
| | | // å¦æè¿æ²¡æè®°å½ç¼ç |
| | | if (!_clientEncodings.ContainsKey(clientId)) |
| | | { |
| | | if (_options.AutoDetectEncoding && _autoDetectedGb2312 != null) |
| | | { |
| | | // èªå¨æ£æµç¼ç ï¼JSON æ UTF-8 åèç¹å¾åç¨ UTF-8ï¼å¦åç¨ GBK |
| | | bool isUtf8 = TryParseJsonSilent(message) || IsLikelyUtf8(_textEncoding.GetBytes(message)); |
| | | _clientEncodings[clientId] = isUtf8 ? _textEncoding : _autoDetectedGb2312; |
| | | } |
| | |
| | | } |
| | | |
| | | /// <summary> |
| | | /// åå
¥æ¶æ¯å°å®¢æ·ç«¯ |
| | | /// 弿¥åéæ¶æ¯å°å®¢æ·ç«¯ |
| | | /// </summary> |
| | | /// <param name="clientId"></param> |
| | | /// <param name="networkStream"></param> |
| | | /// <param name="message"></param> |
| | | /// <param name="cancellationToken"></param> |
| | | /// <returns></returns> |
| | | /// <remarks> |
| | | /// å
鍿¹æ³ï¼ä¸ä½¿ç¨å¸§æ ¼å¼ï¼ç´æ¥åéåå§æ¶æ¯ã |
| | | /// </remarks> |
| | | private async Task WriteToClientAsync(string clientId, NetworkStream networkStream, string message, CancellationToken cancellationToken) |
| | | { |
| | | SemaphoreSlim? sem = null; |
| | |
| | | } |
| | | |
| | | /// <summary> |
| | | /// æ·»å æ¶æ¯å¸§å¤´å°¾ |
| | | /// æå»ºå¸§æ¶æ¯ |
| | | /// </summary> |
| | | /// <param name="message"></param> |
| | | /// <returns></returns> |
| | | /// <remarks> |
| | | /// 卿¶æ¯ååæ·»å 头尾æ è¯ã |
| | | /// </remarks> |
| | | /// <param name="message">åå§æ¶æ¯</param> |
| | | /// <returns>带帧æ è¯çæ¶æ¯</returns> |
| | | private string BuildFramedMessage(string message) |
| | | { |
| | | var header = _options.MessageHeader ?? string.Empty; |
| | |
| | | } |
| | | |
| | | /// <summary> |
| | | /// JSONæ ¼å¼å°è¯è§£æï¼éé»å¤±è´¥ï¼ |
| | | /// éé»å°è¯è§£æ JSON |
| | | /// </summary> |
| | | /// <param name="message"></param> |
| | | /// <returns></returns> |
| | | /// <remarks> |
| | | /// å¤ææ¶æ¯æ¯å¦ä»¥ { æ [ å¼å¤´ï¼å¦ææ¯åå°è¯è§£æã |
| | | /// è§£æå¤±è´¥ä¸æå¼å¸¸ã |
| | | /// </remarks> |
| | | /// <param name="message">æ¶æ¯å
容</param> |
| | | /// <returns>æ¯å¦æ¯ææç JSON æ ¼å¼</returns> |
| | | private static bool TryParseJsonSilent(string message) |
| | | { |
| | | if (string.IsNullOrWhiteSpace(message)) return false; |
| | |
| | | } |
| | | |
| | | /// <summary> |
| | | /// utf-8 å¯è½æ§æ£æµ |
| | | /// 夿åèæ°ç»æ¯å¦ä¸º UTF-8 ç¼ç |
| | | /// </summary> |
| | | /// <param name="data"></param> |
| | | /// <returns></returns> |
| | | /// <remarks> |
| | | /// éè¿æ£æ¥åèåºåæ¯å¦ç¬¦å UTF-8 å¤åèå符çç¼ç è§åã |
| | | /// </remarks> |
| | | /// <param name="data">åèæ°ç»</param> |
| | | /// <returns>æ¯å¦å¯è½æ¯ UTF-8 ç¼ç </returns> |
| | | private static bool IsLikelyUtf8(byte[] data) |
| | | { |
| | | int i = 0; |
| | | while (i < data.Length) |
| | | { |
| | | byte b = data[i]; |
| | | if (b <= 0x7F) { i++; continue; } |
| | | if (b >= 0xC2 && b <= 0xDF) |
| | | if (b <= 0x7F) { i++; continue; } // ASCII å符 |
| | | |
| | | // æ£æ¥å¤åèå符 |
| | | if (b >= 0xC2 && b <= 0xDF) // 2åèå符 |
| | | { |
| | | if (i + 1 >= data.Length) return false; |
| | | if ((data[i + 1] & 0xC0) != 0x80) return false; |
| | | i += 2; continue; |
| | | } |
| | | if (b >= 0xE0 && b <= 0xEF) |
| | | if (b >= 0xE0 && b <= 0xEF) // 3åèå符 |
| | | { |
| | | if (i + 2 >= data.Length) return false; |
| | | if ((data[i + 1] & 0xC0) != 0x80 || (data[i + 2] & 0xC0) != 0x80) return false; |
| | | i += 3; continue; |
| | | } |
| | | if (b >= 0xF0 && b <= 0xF4) |
| | | if (b >= 0xF0 && b <= 0xF4) // 4åèå符 |
| | | { |
| | | if (i + 3 >= data.Length) return false; |
| | | if ((data[i + 1] & 0xC0) != 0x80 || (data[i + 2] & 0xC0) != 0x80 || (data[i + 3] & 0xC0) != 0x80) return false; |
| | |
| | | } |
| | | |
| | | /// <summary> |
| | | /// 读å宿´æ¶æ¯ |
| | | /// æ¥æ¶å®æ´æ¶æ¯ï¼å¸§è§£æï¼ |
| | | /// </summary> |
| | | /// <param name="networkStream">åèæµ</param> |
| | | /// <param name="encoding">ç¼ç æ ¼å¼</param> |
| | | /// <param name="cancellationToken"></param> |
| | | /// <returns></returns> |
| | | /// <remarks> |
| | | /// æ ¹æ®é
ç½®ç头尾æ è¯è§£ææ¶æ¯ã |
| | | /// 妿æªé
置头尾ï¼åä¸ç´è¯»å°æ°æ®ä¸å¯ç¨ã |
| | | /// </remarks> |
| | | /// <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; |
| | |
| | | |
| | | 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) |
| | |
| | | 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 builder.ToString(); |
| | | } |
| | | } |
| | | } |
| | | } |
| | |
| | | using System; |
| | | using System.Collections.Generic; |
| | | using System.Linq; |
| | | using System.Net; |
| | | using System.Net.Sockets; |
| | | using System.Text; |
| | | using System.Text.Json; |
| | | using System.Threading; |
| | | using System.Threading.Tasks; |
| | | using WIDESEAWCS_Core.Helper; |
| | | using System.IO; |
| | | using WIDESEAWCS_Core.LogHelper; |
| | | |
| | | namespace WIDESEAWCS_Tasks.SocketServer |
| | | { |
| | | public partial class TcpSocketServer |
| | | { |
| | | /// <summary> |
| | | /// 弿¥å¯å¨TCPæå¡å¨ï¼ä½¿å
¶å¼å§æ¥åä¼ å
¥ç客æ·ç«¯è¿æ¥ã |
| | | /// 弿¥å¯å¨ TCP Socket æå¡å¨ |
| | | /// </summary> |
| | | /// <remarks>妿æå¡å¨å·²å¨è¿è¡æéè¿é
ç½®ç¦ç¨ï¼æ¤æ¹æ³å°ç«å³è¿åèä¸å¯å¨æå¡å¨ã |
| | | /// åç»ç客æ·ç«¯çæ§åæ¥åæä½å¨åå°ä»»å¡ä¸è¿è¡ãæ¤æ¹æ³ä¸ä¼é»å¡è°ç¨çº¿ç¨ã</remarks> |
| | | /// <param name="cancellationToken">å¯ç¨äºè¯·æ±åæ¶æå¡å¨å¯å¨ååç»åå°æä½ç忶令çã</param> |
| | | /// <returns>è¡¨ç¤ºå¼æ¥å¯å¨æä½çä»»å¡ã彿å¡å¨å¼å§çå¬è¿æ¥æ¶ä»»å¡å®æã</returns> |
| | | /// <remarks> |
| | | /// å建 TCP çå¬å¨å¹¶å¼å§æ¥å客æ·ç«¯è¿æ¥ã |
| | | /// 妿æå¡å¨å·²å¨è¿è¡æè¢«ç¦ç¨ï¼ç´æ¥è¿åã |
| | | /// å¯å¨åå¯å¨æ¥å循ç¯å客æ·ç«¯çæ§ä»»å¡ã |
| | | /// </remarks> |
| | | /// <param name="cancellationToken">忶令ç</param> |
| | | /// <returns>å¯å¨ä»»å¡</returns> |
| | | public Task StartAsync(CancellationToken cancellationToken) |
| | | { |
| | | if (IsRunning || !_options.Enabled) |
| | |
| | | return Task.CompletedTask; |
| | | } |
| | | |
| | | // è§£æçå¬å°å |
| | | IPAddress ipAddress = IPAddress.Any; |
| | | if (IPAddress.TryParse(_options.IpAddress, out IPAddress? parsedAddress)) |
| | | { |
| | | ipAddress = parsedAddress; |
| | | } |
| | | |
| | | // å建çå¬å¨ |
| | | _listener = new TcpListener(ipAddress, _options.Port); |
| | | _listener.Start(_options.Backlog); |
| | | _cts = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken); |
| | | IsRunning = true; |
| | | |
| | | // å¯å¨æ¥å客æ·ç«¯è¿æ¥å¾ªç¯ |
| | | _ = AcceptLoopAsync(_cts.Token); |
| | | |
| | | // å¯å¨å®¢æ·ç«¯çæ§ä»»å¡ï¼æ£æ¥ç©ºé²è¶
æ¶ï¼ |
| | | _monitorTask = Task.Run(() => MonitorClientsAsync(_cts.Token)); |
| | | |
| | | return Task.CompletedTask; |
| | | } |
| | | |
| | | //// <summary> |
| | | /// 弿¥åæ¢æå¡å¨å¹¶çå¾
æææ´»å¨å®¢æ·ç«¯è¿æ¥å®æã |
| | | /// <summary> |
| | | /// 弿¥åæ¢ TCP Socket æå¡å¨ |
| | | /// </summary> |
| | | /// <remarks>妿æå¡å¨æªè¿è¡ï¼æ¤æ¹æ³å°ç«å³è¿åè䏿§è¡ä»»ä½æä½ã |
| | | /// æ¤æ¹æ³ç¡®ä¿ææå®¢æ·ç«¯ä»»å¡å®æåæå°æå¡å¨æ è®°ä¸ºå·²åæ¢ã</remarks> |
| | | /// <param name="cancellationToken">å¯ç¨äºå¨å®æå忶忢æä½ç忶令çã</param> |
| | | /// <returns>è¡¨ç¤ºå¼æ¥åæ¢æä½çä»»å¡ã</returns> |
| | | /// <remarks> |
| | | /// 忢æ¥åæ°è¿æ¥ï¼çå¾
ææå®¢æ·ç«¯ä»»å¡å®æã |
| | | /// </remarks> |
| | | /// <param name="cancellationToken">忶令ç</param> |
| | | /// <returns>忢任å¡</returns> |
| | | public async Task StopAsync(CancellationToken cancellationToken) |
| | | { |
| | | if (!IsRunning) |
| | |
| | | return; |
| | | } |
| | | |
| | | // åéåæ¶ä¿¡å· |
| | | _cts?.Cancel(); |
| | | |
| | | // 忢çå¬ |
| | | _listener?.Stop(); |
| | | |
| | | // çå¾
ææå®¢æ·ç«¯ä»»å¡å®æ |
| | | Task[] tasks; |
| | | lock (_syncRoot) |
| | | { |
| | |
| | | } |
| | | |
| | | /// <summary> |
| | | /// æç»æ¥åä¼ å
¥çTCP客æ·ç«¯è¿æ¥ï¼ç´å°è¯·æ±åæ¶ã |
| | | /// 弿¥æ¥å客æ·ç«¯è¿æ¥çä¸»å¾ªç¯ |
| | | /// </summary> |
| | | /// <remarks>æ¤æ¹æ³æ¨å¨åå°è¿è¡ä»¥å¤çæ°ç客æ·ç«¯è¿æ¥ã |
| | | /// 妿çå¬å¨è¢«éæ¾æéè¿æä¾ç令ç请æ±åæ¶ï¼å¾ªç¯å°éåºã</remarks> |
| | | /// <param name="cancellationToken">å¯ç¨äºè¯·æ±åæ¶æ¥å循ç¯ç令çãå½è¯·æ±åæ¶æ¶ï¼å¾ªç¯å°ç«å³ç»æ¢ã</param> |
| | | /// <returns>è¡¨ç¤ºå¼æ¥æ¥åå¾ªç¯æä½çä»»å¡ã</returns> |
| | | /// <summary> |
| | | /// 弿¥æ¥å客æ·ç«¯è¿æ¥çä¸»å¾ªç¯ |
| | | /// </summary> |
| | | /// <remarks> |
| | | /// å¨åå°çº¿ç¨ä¸æç»æ¥åæ°ç客æ·ç«¯è¿æ¥ã |
| | | /// 彿æ°è¿æ¥æ¶ï¼å°å
¶æ·»å å°å®¢æ·ç«¯åå
¸å¹¶å¯å¨æ¶æ¯å¤çä»»å¡ã |
| | | /// </remarks> |
| | | /// <param name="cancellationToken">忶令ç</param> |
| | | private async Task AcceptLoopAsync(CancellationToken cancellationToken) |
| | | { |
| | | while (!cancellationToken.IsCancellationRequested) |
| | |
| | | TcpClient? client = null; |
| | | try |
| | | { |
| | | // çå¾
客æ·ç«¯è¿æ¥ |
| | | client = await _listener!.AcceptTcpClientAsync().WaitAsync(cancellationToken); |
| | | ConsoleHelper.WriteSuccessLine($"客æ·ç«¯ä¸çº¿:{client.Client.RemoteEndPoint.ToString()}"); |
| | | QuartzLogger.Info($"客æ·ç«¯è¿æ¥:{client.Client.RemoteEndPoint.ToString()}"); |
| | | } |
| | | catch (OperationCanceledException) |
| | | { |
| | | break; |
| | | } |
| | | catch (ObjectDisposedException) |
| | | { |
| | | break; |
| | | } |
| | | catch (OperationCanceledException) { break; } |
| | | catch (ObjectDisposedException) { break; } |
| | | catch |
| | | { |
| | | if (cancellationToken.IsCancellationRequested) |
| | | { |
| | | break; |
| | | } |
| | | if (cancellationToken.IsCancellationRequested) break; |
| | | } |
| | | |
| | | if (client == null) |
| | | { |
| | | continue; |
| | | } |
| | | if (client == null) continue; |
| | | |
| | | // çæå®¢æ·ç«¯ IDï¼ä½¿ç¨è¿ç¨ç«¯ç¹å°åï¼ |
| | | string clientId = GetClientId(client); |
| | | |
| | | // æ·»å å°å®¢æ·ç«¯åå
¸ |
| | | lock (_syncRoot) |
| | | { |
| | | _clients[clientId] = client; |
| | |
| | | } |
| | | |
| | | /// <summary> |
| | | /// ä»å
é¨éåä¸ç§»é¤æå®æ è¯ç¬¦ç客æ·ç«¯ï¼å¹¶éæ¾ç¸å
³èµæºã |
| | | /// ç§»é¤å®¢æ·ç«¯è¿æ¥ |
| | | /// </summary> |
| | | /// <remarks>æ¤æ¹æ³å
³é客æ·ç«¯è¿æ¥ï¼éæ¾ä»»ä½å
³èçéï¼å¹¶ç§»é¤å¯¹å®¢æ·ç«¯çææå¼ç¨ï¼ |
| | | /// å
æ¬è®¾å¤ç»å®åç¼ç ä¿¡æ¯ãéè¿å¯¹å
é¨åæ¥å¯¹è±¡å éç¡®ä¿çº¿ç¨å®å
¨ã</remarks> |
| | | /// <param name="clientId">è¦ç§»é¤ç客æ·ç«¯çå¯ä¸æ è¯ç¬¦ãä¸è½ä¸ºnullæç©ºã</param> |
| | | /// <remarks> |
| | | /// å
³é客æ·ç«¯è¿æ¥å¹¶æ¸
çç¸å
³èµæºï¼ |
| | | /// - å
³é TcpClient |
| | | /// - éæ¾ä¿¡å·é |
| | | /// - ç§»é¤æ´»è·æ¶é´åç¼ç è®°å½ |
| | | /// - ç§»é¤è®¾å¤ç»å® |
| | | /// </remarks> |
| | | /// <param name="clientId">è¦ç§»é¤ç客æ·ç«¯å¯ä¸æ è¯</param> |
| | | private void RemoveClient(string clientId) |
| | | { |
| | | lock (_syncRoot) |
| | | { |
| | | // å
³éå¹¶ç§»é¤å®¢æ·ç«¯è¿æ¥ |
| | | if (_clients.TryGetValue(clientId, out var client)) |
| | | { |
| | | try { client.Close(); } catch { } |
| | | _clients.Remove(clientId); |
| | | } |
| | | |
| | | // éæ¾ä¿¡å·é |
| | | if (_clientLocks.TryGetValue(clientId, out var sem)) |
| | | { |
| | | _clientLocks.Remove(clientId); |
| | | sem.Dispose(); |
| | | } |
| | | |
| | | // ç§»é¤æ´»è·æ¶é´è®°å½ |
| | | _clientLastActive.Remove(clientId); |
| | | |
| | | // ç§»é¤ç¼ç è®°å½ |
| | | _clientEncodings.Remove(clientId); |
| | | |
| | | // ç§»é¤è®¾å¤ç»å® |
| | | var deviceIds = _deviceBindings.Where(kv => kv.Value == clientId).Select(kv => kv.Key).ToList(); |
| | | foreach (var deviceId in deviceIds) |
| | | { |
| | |
| | | } |
| | | |
| | | /// <summary> |
| | | /// 弿¥çæ§å·²è¿æ¥ç客æ·ç«¯ï¼å¹¶æå¼è¶
è¿é
ç½®è¶
æ¶æ¶é´é²ç½®ç客æ·ç«¯è¿æ¥ã |
| | | /// 弿¥çæ§å®¢æ·ç«¯ç©ºé²è¶
æ¶ |
| | | /// </summary> |
| | | /// <remarks>æ¤æ¹æ³æç»æ£æ¥é²ç½®å®¢æ·ç«¯ï¼å¦æå
¶ä¸æ´»å¨æ¶é´è¶
è¿æå®ç空é²è¶
æ¶ï¼åæå¼è¿æ¥ã |
| | | /// çæ§å¾ªç¯å°æç»è¿è¡ï¼ç´å°éè¿æä¾ç令ç请æ±åæ¶ã</remarks> |
| | | /// <param name="cancellationToken">å¯ç¨äºè¯·æ±ç»æ¢çæ§å¾ªç¯ç忶令çã</param> |
| | | /// <returns>è¡¨ç¤ºå¼æ¥çæ§æä½çä»»å¡ã</returns> |
| | | /// <remarks> |
| | | /// å®ææ£æ¥ææå®¢æ·ç«¯çæåæ´»è·æ¶é´ï¼ |
| | | /// 妿è¶
è¿ç©ºé²è¶
æ¶æ¶é´ï¼æå¼è¯¥å®¢æ·ç«¯è¿æ¥ã |
| | | /// </remarks> |
| | | /// <param name="cancellationToken">忶令ç</param> |
| | | private async Task MonitorClientsAsync(CancellationToken cancellationToken) |
| | | { |
| | | while (!cancellationToken.IsCancellationRequested) |
| | |
| | | { |
| | | foreach (var kv in _clientLastActive) |
| | | { |
| | | // æ£æ¥æ¯å¦è¶
è¿ç©ºé²è¶
æ¶ |
| | | if (_options.IdleTimeoutSeconds > 0 && DateTime.Now - kv.Value > TimeSpan.FromSeconds(_options.IdleTimeoutSeconds)) |
| | | { |
| | | toRemove.Add(kv.Key); |
| | |
| | | } |
| | | } |
| | | |
| | | // æå¼è¶
æ¶ç客æ·ç«¯ |
| | | foreach (var cid in toRemove) |
| | | { |
| | | RemoveClient(cid); |
| | | Log($"[{DateTime.Now}] TcpSocketServer disconnect idle client {cid}"); |
| | | } |
| | | } |
| | | catch |
| | | { |
| | | } |
| | | catch { } |
| | | |
| | | // æ¯ç§æ£æ¥ä¸æ¬¡ |
| | | try { await Task.Delay(1000, cancellationToken); } catch { } |
| | | } |
| | | } |
| | | |
| | | /// <summary> |
| | | /// åºäºè¿ç¨ç»ç«¯ç¹è·åæå®TCP客æ·ç«¯çå¯ä¸æ è¯ç¬¦å符串ã |
| | | /// è·å客æ·ç«¯å¯ä¸æ è¯ |
| | | /// </summary> |
| | | /// <remarks>è¿åçæ è¯ç¬¦éç¨äºå¨æ¥å¿è®°å½æè·è¸ªåºæ¯ä¸åºå客æ·ç«¯ã |
| | | /// 妿客æ·ç«¯çè¿ç¨ç»ç«¯ç¹ä¸å¯ç¨ï¼å°çæGUID以确ä¿å¯ä¸æ§ã</remarks> |
| | | /// <param name="client">è¦è·åæ è¯ç¬¦çTCP客æ·ç«¯ãä¸è½ä¸ºnullã</param> |
| | | /// <returns>表示客æ·ç«¯è¿ç¨ç»ç«¯ç¹çå符串ï¼å¦æå¯ç¨ï¼ï¼å¦å为çæçæ°GUIDå符串ã</returns> |
| | | /// <remarks> |
| | | /// 使ç¨å®¢æ·ç«¯çè¿ç¨ç«¯ç¹å°åä½ä¸ºæ è¯ã |
| | | /// 妿è¿ç¨ç«¯ç¹ä¸å¯ç¨ï¼çæéæº GUIDã |
| | | /// </remarks> |
| | | /// <param name="client">TCP 客æ·ç«¯</param> |
| | | /// <returns>客æ·ç«¯æ è¯å符串</returns> |
| | | public static string GetClientId(TcpClient client) |
| | | { |
| | | return client.Client.RemoteEndPoint?.ToString() ?? Guid.NewGuid().ToString(); |
| | |
| | | namespace WIDESEAWCS_Tasks.SocketServer |
| | | { |
| | | /// <summary> |
| | | /// TCP Socketæå¡ç«¯ï¼åºäºè¡åè®®ï¼ææ¢è¡ç¬¦å岿¶æ¯ï¼ |
| | | /// TCP Socket æå¡å¨ - æ ¸å¿ç±» |
| | | /// </summary> |
| | | /// <remarks> |
| | | /// æ ¸å¿èè´£ï¼ |
| | | /// 1. æ¥å客æ·ç«¯ TCP è¿æ¥ |
| | | /// 2. 管ç客æ·ç«¯è¿æ¥ç¶æ |
| | | /// 3. æ¥æ¶ååéæ¶æ¯ |
| | | /// 4. å¤çè®¾å¤æ³¨å |
| | | /// 5. æ¶æ¯å¸§è§£æï¼æ¯æå¤´å°¾æ è¯ï¼ |
| | | /// |
| | | /// æå¡å¨ä½¿ç¨ä»¥ä¸æ°æ®ç»æç®¡ç客æ·ç«¯ï¼ |
| | | /// - _clients: 客æ·ç«¯ ID å° TcpClient çæ å° |
| | | /// - _clientLocks: 客æ·ç«¯ ID å°ä¿¡å·éçæ å°ï¼ä¿è¯æ¯ä¸ªå®¢æ·ç«¯çåéäºæ¥ï¼ |
| | | /// - _deviceBindings: è®¾å¤ ID å°å®¢æ·ç«¯ ID çæ å° |
| | | /// - _clientEncodings: 客æ·ç«¯ ID å°ç¼ç çæ å°ï¼æ¯æèªå¨ç¼ç æ£æµï¼ |
| | | /// - _clientLastActive: 客æ·ç«¯ ID å°æåæ´»è·æ¶é´çæ å° |
| | | /// </remarks> |
| | | public partial class TcpSocketServer : IDisposable |
| | | { |
| | | /// <summary> |
| | | /// æå¡å¨é
ç½®é项 |
| | | /// </summary> |
| | | private readonly SocketServerOptions _options; |
| | | |
| | | /// <summary> |
| | | /// æä¾ä¸ä¸ªå¯ç¨äºåæ¥å¯¹å
å«å®ä¾ç访é®ç对象ã |
| | | /// åæ¥æ ¹å¯¹è±¡ï¼ç¨äºçº¿ç¨åæ¥ |
| | | /// </summary> |
| | | /// <remarks>å¨å¯¹å®ä¾å®ç°çº¿ç¨å®å
¨æä½æ¶ï¼å¯å°æ¤å¯¹è±¡ç¨ä½éå®ç®æ ãæ¤æ¨¡å¼é常ç¨äºé¿å
æ»éå¹¶ç¡®ä¿ä¸è´ç忥ã</remarks> |
| | | public readonly object _syncRoot = new(); |
| | | /// <remarks> |
| | | /// å¨å¤çº¿ç¨è®¿é®å
±äº«æ°æ®ç»ææ¶ä½¿ç¨æ¤å¯¹è±¡è¿è¡åæ¥ã |
| | | /// éç¨ä¿å®çç¥ï¼ç¡®ä¿çº¿ç¨å®å
¨ã |
| | | /// </remarks> |
| | | public readonly object _syncRoot = new object(); |
| | | |
| | | /// <summary> |
| | | /// TCP çå¬å¨ |
| | | /// </summary> |
| | | private TcpListener? _listener; |
| | | |
| | | /// <summary> |
| | | /// 表示ç¨äºååºè¿è¡ä¸æä½çåæ¶è¯·æ±çåæ¶ä»¤çæºã |
| | | /// åæ¶ä»¤çæº |
| | | /// </summary> |
| | | /// <remarks>妿å½åæ²¡ææ´»å¨çåæ¶æºå¶ï¼æ¤å段å¯è½ä¸ºnullãä½¿ç¨æ¤ä»¤çæºåæ¶æ¯æåæ¶ç任塿æä½ã</remarks> |
| | | /// <remarks> |
| | | /// ç¨äºè¯·æ±åæ¢æå¡å¨çè¿è¡ã |
| | | /// </remarks> |
| | | public CancellationTokenSource? _cts; |
| | | |
| | | /// <summary> |
| | | /// æä¾è¡¨ç¤ºæ´»å¨å®¢æ·ç«¯æä½çä»»å¡å表ã |
| | | /// 客æ·ç«¯ä»»å¡å表 |
| | | /// </summary> |
| | | /// <remarks>æ¤å段ç¨äºå
é¨è·è¸ªå¼æ¥å®¢æ·ç«¯æ´»å¨ã宿¯åªè¯»çï¼ä¸åºå¨å
å«ç±»å¤é¨ç´æ¥ä¿®æ¹ã</remarks> |
| | | /// <remarks> |
| | | /// è®°å½æææ´»è·å®¢æ·ç«¯çå¤çä»»å¡ã |
| | | /// </remarks> |
| | | public readonly List<Task> _clientTasks = new(); |
| | | |
| | | /// <summary> |
| | | /// æä¾ä»å®¢æ·ç«¯æ è¯ç¬¦å°å
¶å
³èçTCP客æ·ç«¯è¿æ¥çæ å°ã |
| | | /// 客æ·ç«¯è¿æ¥åå
¸ |
| | | /// </summary> |
| | | /// <remarks>æ¤åå
¸å
许éè¿å¯ä¸å符串æ è¯ç¬¦è®¿é®æ´»å¨çTCP客æ·ç«¯ãå¨å¤çº¿ç¨åºæ¯ä¸ï¼å¯¹éåçä¿®æ¹åºå°å¿è¿è¡ä»¥é¿å
å¹¶åé®é¢ã</remarks> |
| | | /// <remarks> |
| | | /// Key: 客æ·ç«¯ IDï¼éå¸¸æ¯ IP:Portï¼ |
| | | /// Value: TcpClient è¿æ¥å¯¹è±¡ |
| | | /// </remarks> |
| | | public readonly Dictionary<string, TcpClient> _clients = new(); |
| | | |
| | | /// <summary> |
| | | /// æä¾ä»è®¾å¤æ è¯ç¬¦å°å
¶å¯¹åºç»å®å¼çæ å°ã |
| | | /// 设å¤ç»å®åå
¸ |
| | | /// </summary> |
| | | /// <remarks>æ¤å段æ¯åªè¯»çï¼ç¨äºå
å«ç±»å
é¨ä½¿ç¨ãåºéè¿æå®çæ¹æ³æå±æ§å¯¹åå
¸è¿è¡ä¿®æ¹ä»¥ç¡®ä¿ä¸è´æ§ã</remarks> |
| | | /// <remarks> |
| | | /// Key: è®¾å¤ ID |
| | | /// Value: 客æ·ç«¯ ID |
| | | /// ç¨äºéè¿è®¾å¤ ID æ¾å°å¯¹åºç客æ·ç«¯è¿æ¥ã |
| | | /// </remarks> |
| | | public readonly Dictionary<string, string> _deviceBindings = new(); |
| | | |
| | | /// <summary> |
| | | /// æä¾ä»å®¢æ·ç«¯æ è¯ç¬¦å°å
¶å
³èéçæ å°ï¼ç¨äºåæ¥å¯¹å®¢æ·ç«¯ç¹å®èµæºç访é®ã |
| | | /// 客æ·ç«¯éåå
¸ |
| | | /// </summary> |
| | | /// <remarks>åå
¸ä¸çæ¯ä¸ªæ¡ç®å°ä¸ä¸ªå¯ä¸ç客æ·ç«¯IDä¸ä¸ä¸ª<see cref="SemaphoreSlim"/>å®ä¾å
³èï¼å®ç°æ¯ä¸ªå®¢æ·ç«¯ç线ç¨å®å
¨æä½ãæ¤éåç¨äºå
é¨åè°å¹¶å访é®ï¼ä¸åºç´æ¥ä¿®æ¹ã</remarks> |
| | | /// <remarks> |
| | | /// æ¯ä¸ªå®¢æ·ç«¯ä¸ä¸ª SemaphoreSlimï¼ç¡®ä¿åä¸å®¢æ·ç«¯çåéæä½äºæ¥ã |
| | | /// </remarks> |
| | | public readonly Dictionary<string, SemaphoreSlim> _clientLocks = new(); |
| | | |
| | | /// <summary> |
| | | /// æä¾ä»å®¢æ·ç«¯æ è¯ç¬¦å°å
¶å
³èææ¬ç¼ç çæ å°ã |
| | | /// 客æ·ç«¯ç¼ç åå
¸ |
| | | /// </summary> |
| | | /// <remarks>æ¤åå
¸ç¨äºå
é¨è·è¸ªå·²è¿æ¥å®¢æ·ç«¯çç¼ç å好ãé®è¡¨ç¤ºå®¢æ·ç«¯æ è¯ç¬¦ï¼å¼æå®ç¨äºææ¬æä½ç对åº<see cref="System.Text.Encoding"/>ã</remarks> |
| | | /// <remarks> |
| | | /// è®°å½æ¯ä¸ªå®¢æ·ç«¯ä½¿ç¨çå符ç¼ç ã |
| | | /// æ¯æèªå¨æ£æµï¼UTF-8 æ GBKã |
| | | /// </remarks> |
| | | public readonly Dictionary<string, Encoding> _clientEncodings = new(); |
| | | |
| | | /// <summary> |
| | | /// å卿¯ä¸ªå®¢æ·ç«¯æåæ´»å¨çæ¶é´æ³ï¼ä»¥å®¢æ·ç«¯æ è¯ç¬¦ä¸ºé®ã |
| | | /// 客æ·ç«¯æåæ´»è·æ¶é´åå
¸ |
| | | /// </summary> |
| | | /// <remarks>æ¤å段ç¨äºå
é¨è·è¸ªå®¢æ·ç«¯æ´»å¨ãåå
¸å°å®¢æ·ç«¯æ è¯ç¬¦æ å°å°å¯¹åºçæåæ´»å¨æ¶é´ï¼UTCï¼ãç´æ¥ä¿®æ¹æ¤éåå¯è½å½±å客æ·ç«¯ä¼è¯ç®¡çé»è¾ã</remarks> |
| | | /// <remarks> |
| | | /// è®°å½æ¯ä¸ªå®¢æ·ç«¯æå䏿¬¡æ´»å¨çæ¶é´ã |
| | | /// ç¨äºç©ºé²è¶
æ¶æ£æµã |
| | | /// </remarks> |
| | | public readonly Dictionary<string, DateTime> _clientLastActive = new(); |
| | | |
| | | /// <summary> |
| | | /// æå®å
å«ç±»åä¸åç¬¦æ°æ®ä½¿ç¨çææ¬ç¼ç ã |
| | | /// é»è®¤ææ¬ç¼ç |
| | | /// </summary> |
| | | /// <remarks>ä½¿ç¨æ¤å段确å®å¤çåç¬¦æ°æ®æ¶å¦ä½ç¼ç æè§£ç ææ¬ãç¼ç å½±ååèå¦ä½è¢«è§£é为å符ï¼åä¹äº¦ç¶ã常è§çç¼ç å
æ¬UTF8ãASCIIåUnicodeã</remarks> |
| | | public readonly Encoding _textEncoding; |
| | | |
| | | /// <summary> |
| | | /// 表示èªå¨æ£æµå°çGB2312ç¼ç ï¼å¦æå¯ç¨ï¼ã |
| | | /// èªå¨æ£æµç GBK ç¼ç |
| | | /// </summary> |
| | | /// <remarks>é常ä»è¾å
¥æ°æ®ç¡®å®ç¼ç æ¶è®¾ç½®æ¤å段ãå¦ææ£æµå¤±è´¥ææªæ§è¡æ£æµï¼å¼å¯è½ä¸ºnullã</remarks> |
| | | public readonly Encoding? _autoDetectedGb2312; |
| | | |
| | | /// <summary> |
| | | /// æ¥å¿æä»¶è·¯å¾ |
| | | /// </summary> |
| | | private readonly string _logFile; |
| | | |
| | | /// <summary> |
| | | /// 客æ·ç«¯çæ§ä»»å¡ |
| | | /// </summary> |
| | | private Task? _monitorTask; |
| | | |
| | | /// <summary> |
| | | /// ä½¿ç¨æå®çæå¡å¨é项åå§å TcpSocketServer ç±»çæ°å®ä¾ã |
| | | /// æå¡å¨æ¯å¦æ£å¨è¿è¡ |
| | | /// </summary> |
| | | /// <remarks>妿å¯ç¨äº AutoDetectEncoding éé¡¹ï¼æå¡å¨å°é»è®¤ä½¿ç¨ UTF-8 ç¼ç ï¼ |
| | | /// å¹¶å°è¯æ¯æ GBK ç¼ç è¿è¡èªå¨æ£æµã妿ç¼ç æ£æµå¤±è´¥ææä¾äºæ æçç¼ç åç§°ï¼ |
| | | /// å°åéä½¿ç¨ UTF-8 ç¼ç ãæ¥å¿æä»¶è·¯å¾ç± LogFilePath é项å³å®ï¼ |
| | | /// å¦ææªæå®ï¼åé»è®¤ä¸ºåºç¨ç¨åºåºç®å½ä¸ç 'socketserver.log' æä»¶ã</remarks> |
| | | /// <param name="options">奿¥åæå¡å¨çé
ç½®é项ãä¸è½ä¸º nullãæä¾ç¼ç è®¾ç½®ãæ¥å¿æä»¶è·¯å¾åèªå¨æ£æµè¡ä¸ºçé
ç½®ã</param> |
| | | public bool IsRunning { get; private set; } |
| | | |
| | | /// <summary> |
| | | /// æ¶æ¯æ¥æ¶äºä»¶ |
| | | /// </summary> |
| | | /// <remarks> |
| | | /// 彿å¡å¨æ¥æ¶å°æ¶æ¯æ¶è§¦åã |
| | | /// åæ°ï¼æ¶æ¯å
å®¹ãæ¯å¦ JSON æ ¼å¼ãTCP 客æ·ç«¯ãæºå¨äººç¶æ |
| | | /// </remarks> |
| | | public event Func<string, bool, TcpClient, RobotSocketState, Task<string?>>? MessageReceived; |
| | | |
| | | /// <summary> |
| | | /// æºå¨äººè¿æ¥æå¼äºä»¶ |
| | | /// </summary> |
| | | /// <remarks> |
| | | /// 彿ºå¨äººå®¢æ·ç«¯æå¼è¿æ¥æ¶è§¦åã |
| | | /// åæ°ï¼å®¢æ·ç«¯ ID |
| | | /// </remarks> |
| | | public event Func<string, Task<string?>>? RobotReceived; |
| | | |
| | | /// <summary> |
| | | /// æé 彿° |
| | | /// </summary> |
| | | /// <remarks> |
| | | /// ä½¿ç¨æå®çé
ç½®é项åå§å TcpSocketServer å®ä¾ã |
| | | /// é
置项å
æ¬ï¼ç«¯å£ãå符ç¼ç ãèªå¨ç¼ç æ£æµãæ¥å¿æä»¶è·¯å¾çã |
| | | /// </remarks> |
| | | /// <param name="options">Socket æå¡å¨é
ç½®é项</param> |
| | | public TcpSocketServer(IOptions<SocketServerOptions> options) |
| | | { |
| | | _options = options.Value; |
| | | |
| | | // é
ç½®å符ç¼ç |
| | | if (_options.AutoDetectEncoding) |
| | | { |
| | | // èªå¨æ£æµç¼ç 模å¼ï¼é»è®¤ UTF-8ï¼ä¹æ¯æ GBK |
| | | _textEncoding = Encoding.UTF8; |
| | | try { _autoDetectedGb2312 = Encoding.GetEncoding("GBK"); } catch { _autoDetectedGb2312 = null; } |
| | | } |
| | | else |
| | | { |
| | | // æå®ç¼ç æ¨¡å¼ |
| | | try { _textEncoding = Encoding.GetEncoding(_options.EncodingName ?? "utf-8"); } |
| | | catch { _textEncoding = Encoding.UTF8; } |
| | | _autoDetectedGb2312 = null; |
| | | } |
| | | |
| | | // é
ç½®æ¥å¿æä»¶è·¯å¾ |
| | | _logFile = Path.Combine(AppContext.BaseDirectory ?? ".", _options.LogFilePath ?? "socketserver.log"); |
| | | Log($"[{DateTime.Now}] TcpSocketServer starting"); |
| | | } |
| | | |
| | | public bool IsRunning { get; private set; } |
| | | |
| | | public event Func<string, bool, TcpClient, RobotSocketState, Task<string?>>? MessageReceived; |
| | | |
| | | public event Func<string, Task<string?>>? RobotReceived; |
| | | |
| | | /// <summary> |
| | | /// è®°å½æ¥å¿ |
| | | /// </summary> |
| | | /// <remarks> |
| | | /// å°æ¶æ¯è¾åºå°æ§å¶å°å¹¶åå
¥æ¥å¿æä»¶ã |
| | | /// </remarks> |
| | | /// <param name="message">æ¥å¿æ¶æ¯</param> |
| | | private void Log(string message) |
| | | { |
| | | Console.WriteLine(message); |
| | | try { File.AppendAllText(_logFile, message + Environment.NewLine); } catch { } |
| | | } |
| | | } |
| | | } |
| | | } |
| | |
| | | using Quartz; |
| | | using Quartz; |
| | | using System; |
| | | using System.Diagnostics.CodeAnalysis; |
| | | using System.IO; |
| | |
| | | |
| | | namespace WIDESEAWCS_Tasks |
| | | { |
| | | /// <summary> |
| | | /// å åæºä»»å¡ä½ä¸ï¼Quartz Jobï¼- æ ¸å¿è°åº¦é»è¾ |
| | | /// </summary> |
| | | /// <remarks> |
| | | /// Quartz 宿¶ä»»å¡ï¼è´è´£å åæºçä»»å¡è°åº¦ã |
| | | /// ä½¿ç¨ [DisallowConcurrentExecution] ç¦æ¢å¹¶åæ§è¡ï¼ç¡®ä¿åä¸å åæºçä»»å¡ä¸²è¡å¤çã |
| | | /// |
| | | /// æ ¸å¿èè´£ï¼ |
| | | /// 1. ä»é
ç½®æä»¶å è½½å½ä»¤ç±»åæ å° |
| | | /// 2. æ£æ¥å åæºä»»å¡å®æç¶æ |
| | | /// 3. éæ©åéçä»»å¡ï¼å§æç» StackerCraneTaskSelectorï¼ |
| | | /// 4. æå»ºå½ä»¤å¯¹è±¡ï¼å§æç» StackerCraneCommandBuilderï¼ |
| | | /// 5. åéå½ä»¤å°å åæº |
| | | /// 6. å¤çä»»å¡å®æäºä»¶ |
| | | /// |
| | | /// æ¶æè®¾è®¡ï¼ |
| | | /// - StackerCraneTaskSelectorï¼è´è´£éæ©åéçä»»å¡ |
| | | /// - StackerCraneCommandBuilderï¼è´è´£å°ä»»å¡è½¬æ¢ä¸ºå½ä»¤å¯¹è±¡ |
| | | /// - CommonStackerCraneJobï¼è´è´£è°åº¦æµç¨æ§å¶ |
| | | /// </remarks> |
| | | [DisallowConcurrentExecution] |
| | | public class CommonStackerCraneJob : IJob |
| | | { |
| | | /// <summary> |
| | | /// ä»»å¡æå¡ |
| | | /// </summary> |
| | | private readonly ITaskService _taskService; |
| | | |
| | | /// <summary> |
| | | /// 任塿§è¡æç»æå¡ |
| | | /// </summary> |
| | | private readonly ITaskExecuteDetailService _taskExecuteDetailService; |
| | | |
| | | /// <summary> |
| | | /// ä»»å¡ä»å¨ |
| | | /// </summary> |
| | | private readonly ITaskRepository _taskRepository; |
| | | |
| | | /// <summary> |
| | | /// å åæºå½ä»¤é
ç½® |
| | | /// </summary> |
| | | /// <remarks> |
| | | /// å
å«å··éä¸å½ä»¤ç±»åçæ å°å
³ç³»ã |
| | | /// ä» JSON æä»¶å è½½ã |
| | | /// </remarks> |
| | | private readonly StackerCraneCommandConfig _config; |
| | | |
| | | /// <summary> |
| | | /// å åæºä»»å¡éæ©å¨ |
| | | /// </summary> |
| | | /// <remarks> |
| | | /// è´è´£éæ©åéçä»»å¡è¿è¡æ§è¡ã |
| | | /// </remarks> |
| | | private readonly StackerCraneTaskSelector _taskSelector; |
| | | |
| | | /// <summary> |
| | | /// å åæºå½ä»¤æå»ºå¨ |
| | | /// </summary> |
| | | /// <remarks> |
| | | /// è´è´£å°ä»»å¡è½¬æ¢ä¸ºå åæºå¯æ§è¡çå½ä»¤å¯¹è±¡ã |
| | | /// </remarks> |
| | | private readonly StackerCraneCommandBuilder _commandBuilder; |
| | | |
| | | /// <summary> |
| | | /// æé 彿° |
| | | /// </summary> |
| | | /// <param name="taskService">任塿å¡</param> |
| | | /// <param name="taskExecuteDetailService">任塿§è¡æç»æå¡</param> |
| | | /// <param name="taskRepository">ä»»å¡ä»å¨</param> |
| | | /// <param name="routerService">è·¯ç±æå¡</param> |
| | | /// <param name="httpClientHelper">HTTP 客æ·ç«¯å¸®å©ç±»</param> |
| | | public CommonStackerCraneJob( |
| | | ITaskService taskService, |
| | | ITaskExecuteDetailService taskExecuteDetailService, |
| | |
| | | _taskExecuteDetailService = taskExecuteDetailService; |
| | | _taskRepository = taskRepository; |
| | | |
| | | // å è½½é
ç½®æä»¶ |
| | | _config = LoadConfig(); |
| | | |
| | | // åå§åä»»å¡éæ©å¨ |
| | | _taskSelector = new StackerCraneTaskSelector(taskService, routerService, httpClientHelper); |
| | | |
| | | // åå§åå½ä»¤æå»ºå¨ |
| | | _commandBuilder = new StackerCraneCommandBuilder(taskService, routerService, _config); |
| | | } |
| | | |
| | | /// <summary> |
| | | /// å è½½é
ç½®ï¼ä¼å
级ï¼é
ç½®æä»¶ > é»è®¤é
ç½®ï¼ |
| | | /// å è½½é
ç½®æä»¶ï¼ä¼å
级ï¼é
ç½®æä»¶ > é»è®¤é
ç½®ï¼ |
| | | /// </summary> |
| | | /// <remarks> |
| | | /// ä»åºç¨ç¨åºç®å½ä¸ç StackerCraneJob/stackercrane-command-config.json 读åé
ç½®ã |
| | | /// 妿æä»¶ä¸åå¨æè§£æå¤±è´¥ï¼ä½¿ç¨é»è®¤é
ç½®ã |
| | | /// </remarks> |
| | | /// <returns>å åæºå½ä»¤é
ç½®</returns> |
| | | private static StackerCraneCommandConfig LoadConfig() |
| | | { |
| | | try |
| | | { |
| | | // æé é
ç½®æä»¶è·¯å¾ |
| | | string configPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "StackerCraneJob", "stackercrane-command-config.json"); |
| | | if (File.Exists(configPath)) |
| | | { |
| | | // 读åå¹¶è§£æ JSON é
ç½® |
| | | string json = File.ReadAllText(configPath); |
| | | return System.Text.Json.JsonSerializer.Deserialize<StackerCraneCommandConfig>(json) ?? new StackerCraneCommandConfig(); |
| | | } |
| | | } |
| | | catch (Exception ex) |
| | | { |
| | | // é
ç½®å 载失败ï¼ä½¿ç¨é»è®¤é
ç½® |
| | | Console.WriteLine($"é
ç½®å 载失败: {ex.Message}ï¼ä½¿ç¨é»è®¤é
ç½®"); |
| | | } |
| | | |
| | | return new StackerCraneCommandConfig(); |
| | | } |
| | | |
| | | /// <summary> |
| | | /// Quartz Job çæ§è¡å
¥å£ |
| | | /// </summary> |
| | | /// <remarks> |
| | | /// æ§è¡æµç¨ï¼ |
| | | /// 1. ä» JobDataMap è·åå åæºè®¾å¤ä¿¡æ¯ |
| | | /// 2. 订é
ä»»å¡å®æäºä»¶ï¼ä»
ç¬¬ä¸æ¬¡æ§è¡æ¶ï¼ |
| | | /// 3. æ£æ¥å åæºä»»å¡å®æç¶æ |
| | | /// 4. æ£æ¥æ¯å¦å¯ä»¥åéä»»å¡ |
| | | /// 5. éæ©ä»»å¡ |
| | | /// 6. æå»ºå½ä»¤ |
| | | /// 7. åéå½ä»¤ |
| | | /// 8. æ´æ°ä»»å¡ç¶æåå åæºç¶æ |
| | | /// </remarks> |
| | | /// <param name="context">Quartz ä½ä¸æ§è¡ä¸ä¸æ</param> |
| | | public Task Execute(IJobExecutionContext context) |
| | | { |
| | | try |
| | | { |
| | | //Console.WriteLine(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") + " CommonStackerCraneJob Start"); |
| | | |
| | | // ä» JobDataMap è·åå åæºè®¾å¤åæ° |
| | | bool flag = context.JobDetail.JobDataMap.TryGetValue("JobParams", out object? value); |
| | | if (!flag || value is not IStackerCrane commonStackerCrane) |
| | | { |
| | | // åæ°æ æï¼ç´æ¥è¿å |
| | | return Task.CompletedTask; |
| | | } |
| | | |
| | | // 订é
䏿¬¡ä»»å¡å®æäºä»¶ã |
| | | // ========== 订é
ä»»å¡å®æäºä»¶ï¼å
¨å±åªè®¢é
䏿¬¡ï¼ ========== |
| | | if (!commonStackerCrane.IsEventSubscribed) |
| | | { |
| | | // ç»å®ä»»å¡å®æäºä»¶å¤çæ¹æ³ |
| | | commonStackerCrane.StackerCraneTaskCompletedEventHandler += CommonStackerCrane_StackerCraneTaskCompletedEventHandler; |
| | | } |
| | | |
| | | // ========== æ£æ¥å åæºä»»å¡å®æç¶æ ========== |
| | | commonStackerCrane.CheckStackerCraneTaskCompleted(); |
| | | |
| | | // ========== æ£æ¥æ¯å¦å¯ä»¥åéæ°ä»»å¡ ========== |
| | | if (!commonStackerCrane.IsCanSendTask(commonStackerCrane.Communicator, commonStackerCrane.DeviceProDTOs, commonStackerCrane.DeviceProtocolDetailDTOs)) |
| | | { |
| | | // å åæºä¸å¯ç¨ï¼å¦æ£å¨æ§è¡ä¸ä¸ä»»å¡ï¼ï¼ç´æ¥è¿å |
| | | return Task.CompletedTask; |
| | | } |
| | | |
| | | |
| | | // ä»»å¡éæ©ä¸æ²å°ä¸ç¨éæ©å¨ã |
| | | // ========== éæ©ä»»å¡ ========== |
| | | // ä»»å¡éæ©ä¸æ²å°ä¸ç¨éæ©å¨ |
| | | Dt_Task? task = _taskSelector.SelectTask(commonStackerCrane); |
| | | if (task == null) |
| | | { |
| | | // 没æå¯ç¨ä»»å¡ |
| | | return Task.CompletedTask; |
| | | } |
| | | |
| | | // å½ä»¤æå»ºä¸æ²å°ä¸ç¨æå»ºå¨ã |
| | | // ========== æå»ºå½ä»¤ ========== |
| | | // å½ä»¤æå»ºä¸æ²å°ä¸ç¨æå»ºå¨ |
| | | object? stackerCraneTaskCommand = _commandBuilder.ConvertToStackerCraneTaskCommand(task); |
| | | if (stackerCraneTaskCommand == null) |
| | | { |
| | | // å½ä»¤æå»ºå¤±è´¥ |
| | | return Task.CompletedTask; |
| | | } |
| | | |
| | | // ========== åéå½ä»¤ ========== |
| | | bool sendFlag = SendStackerCraneCommand(commonStackerCrane, stackerCraneTaskCommand); |
| | | if (sendFlag) |
| | | { |
| | | // åéæåï¼æ´æ°ç¶æ |
| | | commonStackerCrane.LastTaskType = task.TaskType; |
| | | _taskService.UpdateTaskStatusToNext(task.TaskNum); |
| | | } |
| | | } |
| | | catch (Exception ex) |
| | | { |
| | | // è®°å½å¼å¸¸ |
| | | Console.WriteLine($"CommonStackerCraneJob Error: {ex.Message}"); |
| | | } |
| | | |
| | |
| | | } |
| | | |
| | | /// <summary> |
| | | /// ä»»å¡å®æäºä»¶è®¢é
çæ¹æ³ |
| | | /// å åæºä»»å¡å®æäºä»¶å¤ç |
| | | /// </summary> |
| | | /// <remarks> |
| | | /// å½å åæºæ¥åä»»å¡å®ææ¶è°ç¨æ¤æ¹æ³ã |
| | | /// å¤çï¼ |
| | | /// 1. è®°å½æ¥å¿ |
| | | /// 2. æ´æ°ä»»å¡ç¶æä¸ºå®æ |
| | | /// 3. æ¸
é¤å åæºçä½ä¸æä»¤ |
| | | /// </remarks> |
| | | /// <param name="sender">äºä»¶åéè
ï¼å åæºè®¾å¤ï¼</param> |
| | | /// <param name="e">äºä»¶åæ°ï¼å
å«å®æçä»»å¡å·</param> |
| | | private void CommonStackerCrane_StackerCraneTaskCompletedEventHandler(object? sender, StackerCraneTaskCompletedEventArgs e) |
| | | { |
| | | CommonStackerCrane? commonStackerCrane = sender as CommonStackerCrane; |
| | | if (commonStackerCrane != null) |
| | | IStackerCrane? stackerCrane = sender as IStackerCrane; |
| | | if (stackerCrane != null) |
| | | { |
| | | // è®°å½æ¥å¿ |
| | | Console.Out.WriteLine("TaskCompleted" + e.TaskNum); |
| | | |
| | | // æ´æ°ä»»å¡ç¶æä¸ºå®æ |
| | | _taskService.StackCraneTaskCompleted(e.TaskNum); |
| | | commonStackerCrane.SetValue(StackerCraneDBName.WorkAction, 2); |
| | | |
| | | // æ¸
é¤å åæºçä½ä¸æä»¤ï¼è®¾ç½®ä¸º 2ï¼è¡¨ç¤ºç©ºé²ï¼ |
| | | stackerCrane.SetValue(StackerCraneDBName.WorkAction, 2); |
| | | } |
| | | } |
| | | |
| | | /// <summary> |
| | | /// åéå åæºå½ä»¤ |
| | | /// </summary> |
| | | /// <remarks> |
| | | /// æ ¹æ®å½ä»¤ç±»åè°ç¨ç¸åºçåéæ¹æ³ã |
| | | /// æ¯ææ åå½ä»¤åæåå½ä»¤ä¸¤ç§æ ¼å¼ã |
| | | /// </remarks> |
| | | /// <param name="commonStackerCrane">å åæºè®¾å¤å¯¹è±¡</param> |
| | | /// <param name="command">å½ä»¤å¯¹è±¡</param> |
| | | /// <returns>å鿝妿å</returns> |
| | | private static bool SendStackerCraneCommand(IStackerCrane commonStackerCrane, object command) |
| | | { |
| | | return command switch |
| | | { |
| | | // æåå½ä»¤ï¼å¦ HC å··éï¼ |
| | | FormationStackerCraneTaskCommand formationCommand => commonStackerCrane.SendCommand(formationCommand), |
| | | // æ åå½ä»¤ï¼å¦ GWãCW å··éï¼ |
| | | StackerCraneTaskCommand standardCommand => commonStackerCrane.SendCommand(standardCommand), |
| | | // æªç¥å½ä»¤ç±»å |
| | | _ => false |
| | | }; |
| | | } |
| | |
| | | using System; |
| | | using System; |
| | | using System.Diagnostics.CodeAnalysis; |
| | | using WIDESEAWCS_Common.TaskEnum; |
| | | using WIDESEAWCS_ITaskInfoService; |
| | |
| | | namespace WIDESEAWCS_Tasks |
| | | { |
| | | /// <summary> |
| | | /// å åæºå½ä»¤æå»ºå¨ï¼å°è£
ä»»å¡å°å½ä»¤å¯¹è±¡ç转æ¢ä¸å°åè§£æã |
| | | /// å åæºå½ä»¤æå»ºå¨ - å°è£
ä»»å¡å°å½ä»¤å¯¹è±¡ç转æ¢ä¸å°åè§£æ |
| | | /// </summary> |
| | | /// <remarks> |
| | | /// æ ¸å¿èè´£ï¼ |
| | | /// 1. æ ¹æ®å··éç±»åéæ©å½ä»¤æ ¼å¼ï¼æ åå½ä»¤/æåå½ä»¤ï¼ |
| | | /// 2. æå»ºå
¥åºãåºåºãç§»åºä»»å¡çå½ä»¤å¯¹è±¡ |
| | | /// 3. è§£æä»»å¡å°åï¼è¡-å-屿 ¼å¼ï¼å°å½ä»¤åæ |
| | | /// 4. æ¥è¯¢è·¯ç±ä¿¡æ¯ï¼ç¡®å®å åæºçåè´§/æ¾è´§ç«å° |
| | | /// |
| | | /// å°åæ ¼å¼çº¦å®ï¼å°ååç¬¦ä¸²æ ¼å¼ä¸º "è¡-å-å±"ï¼ä¾å¦ "1-2-3" 表示第1è¡ã第2åã第3å±ã |
| | | /// </remarks> |
| | | public class StackerCraneCommandBuilder |
| | | { |
| | | /// <summary> |
| | | /// ä»»å¡æå¡ |
| | | /// </summary> |
| | | private readonly ITaskService _taskService; |
| | | |
| | | /// <summary> |
| | | /// è·¯ç±æå¡ |
| | | /// </summary> |
| | | private readonly IRouterService _routerService; |
| | | |
| | | /// <summary> |
| | | /// å åæºå½ä»¤é
ç½® |
| | | /// </summary> |
| | | private readonly StackerCraneCommandConfig _config; |
| | | |
| | | /// <summary> |
| | | /// æé 彿° |
| | | /// </summary> |
| | | /// <param name="taskService">任塿å¡</param> |
| | | /// <param name="routerService">è·¯ç±æå¡</param> |
| | | /// <param name="config">å½ä»¤é
ç½®</param> |
| | | public StackerCraneCommandBuilder( |
| | | ITaskService taskService, |
| | | IRouterService routerService, |
| | |
| | | _config = config; |
| | | } |
| | | |
| | | /// <summary> |
| | | /// å°ä»»å¡è½¬æ¢ä¸ºå åæºå½ä»¤ |
| | | /// </summary> |
| | | /// <remarks> |
| | | /// æ ¹æ®å··éç±»åéæ©ä¸åçå½ä»¤æå»ºçç¥ã |
| | | /// </remarks> |
| | | /// <param name="task">ä»»å¡å¯¹è±¡</param> |
| | | /// <returns>å åæºå½ä»¤å¯¹è±¡ï¼è½¬æ¢å¤±è´¥è¿å null</returns> |
| | | public object? ConvertToStackerCraneTaskCommand([NotNull] Dt_Task task) |
| | | { |
| | | // æ ¹æ®å··éè·åå½ä»¤ç±»å |
| | | string commandType = GetCommandType(task.Roadway); |
| | | |
| | | // æ ¹æ®å½ä»¤ç±»åè°ç¨ç¸åºçæå»ºæ¹æ³ |
| | | return commandType switch |
| | | { |
| | | "Formation" => BuildCommand(task, CreateFormationCommand(task)), |
| | | _ => BuildCommand(task, CreateStandardCommand(task)) |
| | | "Formation" => BuildCommand(task, CreateFormationCommand(task)), // æåå½ä»¤ |
| | | _ => BuildCommand(task, CreateStandardCommand(task)) // æ åå½ä»¤ |
| | | }; |
| | | } |
| | | |
| | | /// <summary> |
| | | /// æ ¹æ®å··éè·åå½ä»¤ç±»å |
| | | /// </summary> |
| | | /// <remarks> |
| | | /// éåé
ç½®ä¸çæ å°å
³ç³»ï¼æ¾å°å¹é
çå½ä»¤ç±»åã |
| | | /// 妿ä¸å¹é
任使 å°ï¼è¿åé»è®¤å½ä»¤ç±»åã |
| | | /// </remarks> |
| | | /// <param name="roadway">å··éç¼ç </param> |
| | | /// <returns>å½ä»¤ç±»åï¼Standard æ Formationï¼</returns> |
| | | private string GetCommandType(string roadway) |
| | | { |
| | | foreach (var mapping in _config.RoadwayCommandMapping) |
| | |
| | | return _config.DefaultCommandType; |
| | | } |
| | | |
| | | /// <summary> |
| | | /// å建æ åå½ä»¤ |
| | | /// </summary> |
| | | /// <remarks> |
| | | /// ç¨äºæ åå åæºï¼GWãCW å¼å¤´å··éï¼ã |
| | | /// </remarks> |
| | | /// <param name="task">ä»»å¡å¯¹è±¡</param> |
| | | /// <returns>æ åå½ä»¤å¯¹è±¡</returns> |
| | | private static StackerCraneTaskCommand CreateStandardCommand(Dt_Task task) |
| | | { |
| | | return new StackerCraneTaskCommand |
| | | { |
| | | TaskNum = task.TaskNum, |
| | | WorkType = 1, |
| | | WorkAction = 1 |
| | | TaskNum = task.TaskNum, // ä»»å¡å· |
| | | WorkType = 1, // ä½ä¸ç±»å |
| | | WorkAction = 1 // ä½ä¸æä»¤ï¼å¼å§æ§è¡ |
| | | }; |
| | | } |
| | | |
| | | /// <summary> |
| | | /// å建æåå½ä»¤ |
| | | /// </summary> |
| | | /// <remarks> |
| | | /// ç¨äºæåå åæºï¼HC å¼å¤´å··éï¼ã |
| | | /// å
嫿¡ç åæ®µï¼ç¨äºçµæ± 追溯ã |
| | | /// </remarks> |
| | | /// <param name="task">ä»»å¡å¯¹è±¡</param> |
| | | /// <returns>æåå½ä»¤å¯¹è±¡</returns> |
| | | private static FormationStackerCraneTaskCommand CreateFormationCommand(Dt_Task task) |
| | | { |
| | | return new FormationStackerCraneTaskCommand |
| | | { |
| | | Barcode = task.PalletCode, |
| | | TaskNum = task.TaskNum, |
| | | WorkType = 1, |
| | | WorkAction = 1, |
| | | FireAlarm = 0, |
| | | HeartBeat = 0, |
| | | FieldName = string.Empty |
| | | Barcode = task.PalletCode, // æçæ¡ç |
| | | TaskNum = task.TaskNum, // ä»»å¡å· |
| | | WorkType = 1, // ä½ä¸ç±»å |
| | | WorkAction = 1, // ä½ä¸æä»¤ï¼å¼å§æ§è¡ |
| | | FireAlarm = 0, // ç«è¦ï¼æ£å¸¸ |
| | | HeartBeat = 0, // å¿è·³ |
| | | FieldName = string.Empty // ä¿çåæ®µ |
| | | }; |
| | | } |
| | | |
| | | /// <summary> |
| | | /// æå»ºå½ä»¤ï¼éç¨ï¼ |
| | | /// </summary> |
| | | /// <remarks> |
| | | /// æ ¹æ®ä»»å¡ç±»åï¼å
¥åº/åºåº/ç§»åºï¼è°ç¨ç¸åºçæå»ºæ¹æ³ã |
| | | /// </remarks> |
| | | /// <typeparam name="T">å½ä»¤ç±»å</typeparam> |
| | | /// <param name="task">ä»»å¡å¯¹è±¡</param> |
| | | /// <param name="command">åå§å½ä»¤å¯¹è±¡</param> |
| | | /// <returns>å¡«å
好çå½ä»¤å¯¹è±¡</returns> |
| | | private T? BuildCommand<T>(Dt_Task task, T command) where T : class |
| | | { |
| | | // è·åä»»å¡ç±»ååç» |
| | | TaskTypeGroup taskTypeGroup = task.TaskType.GetTaskTypeGroup(); |
| | | |
| | | // æ ¹æ®ä»»å¡ç±»åååæå»º |
| | | return taskTypeGroup switch |
| | | { |
| | | TaskTypeGroup.InboundGroup => BuildInboundCommand(task, command), |
| | | TaskTypeGroup.OutbondGroup => BuildOutboundCommand(task, command), |
| | | TaskTypeGroup.RelocationGroup => BuildRelocationCommand(task, command), |
| | | _ => command |
| | | TaskTypeGroup.InboundGroup => BuildInboundCommand(task, command), // å
¥åº |
| | | TaskTypeGroup.OutbondGroup => BuildOutboundCommand(task, command), // åºåº |
| | | TaskTypeGroup.RelocationGroup => BuildRelocationCommand(task, command), // ç§»åº |
| | | _ => command // æªç¥ç±»åï¼è¿ååå½ä»¤ |
| | | }; |
| | | } |
| | | |
| | | /// <summary> |
| | | /// æå»ºå
¥åºå½ä»¤ |
| | | /// </summary> |
| | | /// <remarks> |
| | | /// å
¥åºä»»å¡éè¦ï¼ |
| | | /// 1. æ¥è¯¢å åæºåè´§ç«å°ï¼æ ¹æ®å½åå°ååä»»å¡ç±»åï¼ |
| | | /// 2. 设置起å§åæ ï¼æ¥èªç«å°ï¼ |
| | | /// 3. è§£æç®æ å°åï¼è®¾ç½®ç»ç¹åæ |
| | | /// </remarks> |
| | | /// <typeparam name="T">å½ä»¤ç±»å</typeparam> |
| | | /// <param name="task">ä»»å¡å¯¹è±¡</param> |
| | | /// <param name="command">å½ä»¤å¯¹è±¡</param> |
| | | /// <returns>å¡«å
好çå½ä»¤å¯¹è±¡</returns> |
| | | private T? BuildInboundCommand<T>(Dt_Task task, T command) where T : class |
| | | { |
| | | // ç¡®å®ä»»å¡ç±»åï¼ç©ºæçç¨ç¹æ®ç±»å 100ï¼ |
| | | int taskType = 0; |
| | | if (task.TaskType == (int)TaskOutboundTypeEnum.OutEmpty) |
| | | { |
| | |
| | | } |
| | | else |
| | | taskType = task.TaskType; |
| | | |
| | | // æ¥è¯¢å åæºåè´§ç«å°è·¯ç± |
| | | Dt_Router? router = _routerService.QueryNextRoute(task.CurrentAddress, task.Roadway, taskType); |
| | | if (router == null) |
| | | { |
| | | // æªæ¾å°ç«å°ï¼æ´æ°å¼å¸¸ä¿¡æ¯ |
| | | _taskService.UpdateTaskExceptionMessage(task.TaskNum, $"æªæ¾å°ç«å°ã{task.CurrentAddress}ãä¿¡æ¯ï¼æ æ³è·å对åºçå åæºåè´§ç«å°ä¿¡æ¯"); |
| | | return null; |
| | | } |
| | | |
| | | // 设置起å§åæ ï¼æ¥èªè·¯ç±é
ç½®ï¼ |
| | | SetCommandProperty(command, "StartRow", Convert.ToInt16(router.SrmRow)); |
| | | SetCommandProperty(command, "StartColumn", Convert.ToInt16(router.SrmColumn)); |
| | | SetCommandProperty(command, "StartLayer", Convert.ToInt16(router.SrmLayer)); |
| | | |
| | | // è§£æç®æ å°åï¼åºä½å°åï¼ |
| | | if (!TryParseAddress(task.NextAddress, out short endRow, out short endColumn, out short endLayer)) |
| | | { |
| | | _taskService.UpdateTaskExceptionMessage(task.TaskNum, $"å
¥åºä»»å¡ç»ç¹é误ï¼ç»ç¹ï¼ã{task.NextAddress}ã"); |
| | | return null; |
| | | } |
| | | |
| | | // 设置ç»ç¹åæ |
| | | SetCommandProperty(command, "EndRow", endRow); |
| | | SetCommandProperty(command, "EndColumn", endColumn); |
| | | SetCommandProperty(command, "EndLayer", endLayer); |
| | |
| | | return command; |
| | | } |
| | | |
| | | /// <summary> |
| | | /// æå»ºåºåºå½ä»¤ |
| | | /// </summary> |
| | | /// <remarks> |
| | | /// åºåºä»»å¡éè¦ï¼ |
| | | /// 1. æ¥è¯¢å åæºæ¾è´§ç«å°ï¼æ ¹æ®ç®æ å°ååä»»å¡ç±»åï¼ |
| | | /// 2. 设置ç»ç¹åæ ï¼æ¥èªç«å°ï¼ |
| | | /// 3. è§£æèµ·å§å°åï¼è®¾ç½®èµ·ç¹åæ |
| | | /// </remarks> |
| | | /// <typeparam name="T">å½ä»¤ç±»å</typeparam> |
| | | /// <param name="task">ä»»å¡å¯¹è±¡</param> |
| | | /// <param name="command">å½ä»¤å¯¹è±¡</param> |
| | | /// <returns>å¡«å
好çå½ä»¤å¯¹è±¡</returns> |
| | | private T? BuildOutboundCommand<T>(Dt_Task task, T command) where T : class |
| | | { |
| | | // ç¡®å®ä»»å¡ç±»å |
| | | int taskType = 0; |
| | | if (task.TaskType == (int)TaskOutboundTypeEnum.OutEmpty) |
| | | { |
| | |
| | | else |
| | | taskType = task.TaskType; |
| | | |
| | | // æ¥è¯¢å åæºæ¾è´§ç«å°è·¯ç± |
| | | Dt_Router? router = _routerService.QueryNextRoute(task.Roadway, task.TargetAddress, taskType); |
| | | if (router == null) |
| | | { |
| | |
| | | return null; |
| | | } |
| | | |
| | | // 设置ç»ç¹åæ ï¼æ¥èªè·¯ç±é
ç½®ï¼ |
| | | SetCommandProperty(command, "EndRow", Convert.ToInt16(router.SrmRow)); |
| | | SetCommandProperty(command, "EndColumn", Convert.ToInt16(router.SrmColumn)); |
| | | SetCommandProperty(command, "EndLayer", Convert.ToInt16(router.SrmLayer)); |
| | | |
| | | // è§£æèµ·å§å°åï¼åºä½å°åï¼ |
| | | if (!TryParseAddress(task.CurrentAddress, out short startRow, out short startColumn, out short startLayer)) |
| | | { |
| | | _taskService.UpdateTaskExceptionMessage(task.TaskNum, $"åºåºä»»å¡èµ·ç¹é误ï¼èµ·ç¹ï¼ã{task.CurrentAddress}ã"); |
| | | return null; |
| | | } |
| | | |
| | | // 设置起ç¹åæ |
| | | SetCommandProperty(command, "StartRow", startRow); |
| | | SetCommandProperty(command, "StartColumn", startColumn); |
| | | SetCommandProperty(command, "StartLayer", startLayer); |
| | |
| | | return command; |
| | | } |
| | | |
| | | /// <summary> |
| | | /// æå»ºç§»åºå½ä»¤ |
| | | /// </summary> |
| | | /// <remarks> |
| | | /// ç§»åºä»»å¡éè¦ï¼ |
| | | /// 1. è§£æç®æ å°åï¼æ°çåºä½ï¼ |
| | | /// 2. è§£æèµ·å§å°åï¼åæ¥çåºä½ï¼ |
| | | /// 3. 设置起æ¢åæ |
| | | /// </remarks> |
| | | /// <typeparam name="T">å½ä»¤ç±»å</typeparam> |
| | | /// <param name="task">ä»»å¡å¯¹è±¡</param> |
| | | /// <param name="command">å½ä»¤å¯¹è±¡</param> |
| | | /// <returns>å¡«å
好çå½ä»¤å¯¹è±¡</returns> |
| | | private T? BuildRelocationCommand<T>(Dt_Task task, T command) where T : class |
| | | { |
| | | // è§£æç®æ å°å |
| | | if (!TryParseAddress(task.NextAddress, out short endRow, out short endColumn, out short endLayer)) |
| | | { |
| | | _taskService.UpdateTaskExceptionMessage(task.TaskNum, $"ç§»åºä»»å¡ç»ç¹é误ï¼ç»ç¹ï¼ã{task.NextAddress}ã"); |
| | | return null; |
| | | } |
| | | |
| | | // 设置ç»ç¹åæ |
| | | SetCommandProperty(command, "EndRow", endRow); |
| | | SetCommandProperty(command, "EndColumn", endColumn); |
| | | SetCommandProperty(command, "EndLayer", endLayer); |
| | | |
| | | // è§£æèµ·å§å°å |
| | | if (!TryParseAddress(task.CurrentAddress, out short startRow, out short startColumn, out short startLayer)) |
| | | { |
| | | _taskService.UpdateTaskExceptionMessage(task.TaskNum, $"ç§»åºä»»å¡èµ·ç¹é误ï¼èµ·ç¹ï¼ã{task.CurrentAddress}ã"); |
| | | return null; |
| | | } |
| | | |
| | | // 设置起ç¹åæ |
| | | SetCommandProperty(command, "StartRow", startRow); |
| | | SetCommandProperty(command, "StartColumn", startColumn); |
| | | SetCommandProperty(command, "StartLayer", startLayer); |
| | |
| | | return command; |
| | | } |
| | | |
| | | /// <summary> |
| | | /// 设置å½ä»¤å±æ§å¼ï¼éè¿åå°ï¼ |
| | | /// </summary> |
| | | /// <remarks> |
| | | /// 使ç¨åå°å¨æè®¾ç½®å½ä»¤å¯¹è±¡ç屿§å¼ã |
| | | /// </remarks> |
| | | /// <typeparam name="T">å½ä»¤ç±»å</typeparam> |
| | | /// <param name="command">å½ä»¤å¯¹è±¡</param> |
| | | /// <param name="propertyName">屿§åç§°</param> |
| | | /// <param name="value">屿§å¼</param> |
| | | private static void SetCommandProperty<T>(T command, string propertyName, object value) where T : class |
| | | { |
| | | var property = typeof(T).GetProperty(propertyName); |
| | | property?.SetValue(command, value); |
| | | } |
| | | |
| | | /// <summary> |
| | | /// è§£æå°åå符串 |
| | | /// </summary> |
| | | /// <remarks> |
| | | /// å°åæ ¼å¼ï¼è¡-å-å±ï¼ä¾å¦ "1-2-3" 表示第1è¡ã第2åã第3å±ã |
| | | /// </remarks> |
| | | /// <param name="address">å°åå符串</param> |
| | | /// <param name="row">è§£æåºçè¡åæ </param> |
| | | /// <param name="column">è§£æåºçååæ </param> |
| | | /// <param name="layer">è§£æåºçå±åæ </param> |
| | | /// <returns>è§£ææåè¿å true</returns> |
| | | private static bool TryParseAddress(string address, out short row, out short column, out short layer) |
| | | { |
| | | row = column = layer = 0; |
| | | |
| | | string[] parts = address.Split("-"); |
| | | // æ "-" åéå°å |
| | | string[] parts = address.Split('-'); |
| | | if (parts.Length != 3) |
| | | { |
| | | return false; |
| | | } |
| | | |
| | | // è§£æåé¨å为 short ç±»å |
| | | return short.TryParse(parts[0], out row) |
| | | && short.TryParse(parts[1], out column) |
| | | && short.TryParse(parts[2], out layer); |
| | |
| | | /// <summary> |
| | | /// å åæºå½ä»¤é
ç½® |
| | | /// </summary> |
| | | /// <remarks> |
| | | /// å®ä¹å åæºå½ä»¤ç±»åä¸å··éçæ å°å
³ç³»ã |
| | | /// æ ¹æ®å··éï¼Roadwayï¼çä¸åï¼å åæºå¯è½ä½¿ç¨ä¸åçå½ä»¤æ ¼å¼ã |
| | | /// é
ç½®å¯ä»¥éè¿ JSON æä»¶å¨æå è½½ã |
| | | /// </remarks> |
| | | public class StackerCraneCommandConfig |
| | | { |
| | | /// <summary> |
| | | /// Roadway å
³é®åå°å½ä»¤ç±»åçæ å° |
| | | /// å··éå
³é®åå°å½ä»¤ç±»åçæ å°åå
¸ |
| | | /// </summary> |
| | | /// <remarks> |
| | | /// Key: å··éç¼ç çå
³é®åï¼å¦ HCãGWãCWï¼ |
| | | /// Value: å½ä»¤ç±»åï¼å¦ FormationãStandardï¼ |
| | | /// |
| | | /// æ å°è§åï¼ |
| | | /// - HC å¼å¤´ -> Formationï¼æåå åæºå½ä»¤ï¼ |
| | | /// - GW å¼å¤´ -> Standardï¼æ åå åæºå½ä»¤ï¼ |
| | | /// - CW å¼å¤´ -> Standardï¼æ åå åæºå½ä»¤ï¼ |
| | | /// </remarks> |
| | | public Dictionary<string, string> RoadwayCommandMapping { get; set; } = new() |
| | | { |
| | | { "HC", "Formation" }, |
| | | { "GW", "Standard" }, |
| | | { "CW", "Standard" } |
| | | { "HC", "Formation" }, // æåå åæº |
| | | { "GW", "Standard" }, // æ åå åæº |
| | | { "CW", "Standard" } // æ åå åæº |
| | | }; |
| | | |
| | | /// <summary> |
| | | /// é»è®¤å½ä»¤ç±»å |
| | | /// </summary> |
| | | /// <remarks> |
| | | /// å½å··éç¼ç ä¸å¹é
任使 å°è§åæ¶ä½¿ç¨çé»è®¤å½ä»¤ç±»åã |
| | | /// é»è®¤ä¸º Standardï¼æ åå½ä»¤æ ¼å¼ï¼ã |
| | | /// </remarks> |
| | | public string DefaultCommandType { get; set; } = "Standard"; |
| | | } |
| | | } |
| | |
| | | #region << ç æ¬ 注 é >> |
| | | /*---------------------------------------------------------------- |
| | | * å½å空é´ï¼WIDESEAWCS_Tasks.StackerCraneJob |
| | | * å建è
ï¼è¡ç«¥åº |
| | | * å建æ¶é´ï¼2024/8/2 16:13:36 |
| | | * çæ¬ï¼V1.0.0 |
| | | * æè¿°ï¼ |
| | | * |
| | | * ---------------------------------------------------------------- |
| | | * ä¿®æ¹äººï¼ |
| | | * ä¿®æ¹æ¶é´ï¼ |
| | | * çæ¬ï¼V1.0.1 |
| | | * ä¿®æ¹è¯´æï¼ |
| | | * |
| | | *----------------------------------------------------------------*/ |
| | | #endregion << ç æ¬ 注 é >> |
| | | |
| | | using System; |
| | | using System.Collections.Generic; |
| | | using System.Linq; |
| | | using System.Text; |
| | | using System.Threading.Tasks; |
| | | |
| | | namespace WIDESEAWCS_Tasks.StackerCraneJob |
| | | { |
| | | /// <summary> |
| | | /// å åæº PLC å¯åå¨åç§°æä¸¾ |
| | | /// </summary> |
| | | /// <remarks> |
| | | /// å®ä¹å åæºä¸ WCS éä¿¡æ¶ä½¿ç¨ç PLC å¯åå¨å°ååç§°ã |
| | | /// å
å«ä»»å¡å·ãä½ä¸ç±»åãèµ·æ¢ä½ç½®çä¿¡æ¯ã |
| | | /// </remarks> |
| | | public enum StackerCraneDBName |
| | | { |
| | | /// <summary> |
| | | /// ä»»å¡å· |
| | | /// </summary> |
| | | /// <remarks> |
| | | /// WCS åé
çä»»å¡å¯ä¸æ è¯å·ã |
| | | /// ç¨äº WCS åå åæºä¹é´å»ºç«ä»»å¡å¯¹åºçå
³èã |
| | | /// </remarks> |
| | | TaskNum, |
| | | |
| | | /// <summary> |
| | | /// ä½ä¸ç±»å |
| | | /// </summary> |
| | | /// <remarks> |
| | | /// æ è¯ä»»å¡çç±»åã |
| | | /// </remarks> |
| | | WorkType, |
| | | |
| | | /// <summary> |
| | | /// æçç±»å |
| | | /// </summary> |
| | | /// <remarks> |
| | | /// æ è¯æççè§æ ¼ç±»åã |
| | | /// </remarks> |
| | | TrayType, |
| | | |
| | | /// <summary> |
| | | /// èµ·å§è¡ |
| | | /// </summary> |
| | | /// <remarks> |
| | | /// ä»»å¡çèµ·å§ä½ç½®-è¡åæ ã |
| | | /// ç¨äºç¡®å®åºä½å¨è´§æ¶ä¸çè¡ä½ç½®ã |
| | | /// </remarks> |
| | | StartRow, |
| | | |
| | | /// <summary> |
| | | /// èµ·å§å |
| | | /// </summary> |
| | | /// <remarks> |
| | | /// ä»»å¡çèµ·å§ä½ç½®-ååæ ã |
| | | /// ç¨äºç¡®å®åºä½å¨è´§æ¶ä¸çåä½ç½®ã |
| | | /// </remarks> |
| | | StartColumn, |
| | | |
| | | /// <summary> |
| | | /// èµ·å§å± |
| | | /// </summary> |
| | | /// <remarks> |
| | | /// ä»»å¡çèµ·å§ä½ç½®-å±åæ ã |
| | | /// ç¨äºç¡®å®åºä½å¨è´§æ¶ä¸çå±ä½ç½®ã |
| | | /// </remarks> |
| | | StartLayer, |
| | | |
| | | /// <summary> |
| | | /// ç®æ è¡ |
| | | /// </summary> |
| | | /// <remarks> |
| | | /// ä»»å¡çç®æ ä½ç½®-è¡åæ ã |
| | | /// å
¥åºæ¶è¡¨ç¤ºè´§ç©åæ¾çè¡ä½ç½®ï¼åºåºæ¶è¡¨ç¤ºè´§ç©æ¥æºçè¡ä½ç½®ã |
| | | /// </remarks> |
| | | EndRow, |
| | | |
| | | /// <summary> |
| | | /// ç®æ å |
| | | /// </summary> |
| | | /// <remarks> |
| | | /// ä»»å¡çç®æ ä½ç½®-ååæ ã |
| | | /// å
¥åºæ¶è¡¨ç¤ºè´§ç©åæ¾çåä½ç½®ï¼åºåºæ¶è¡¨ç¤ºè´§ç©æ¥æºçåä½ç½®ã |
| | | /// </remarks> |
| | | EndColumn, |
| | | |
| | | /// <summary> |
| | | /// ç®æ å± |
| | | /// </summary> |
| | | /// <remarks> |
| | | /// ä»»å¡çç®æ ä½ç½®-å±åæ ã |
| | | /// å
¥åºæ¶è¡¨ç¤ºè´§ç©åæ¾çå±ä½ç½®ï¼åºåºæ¶è¡¨ç¤ºè´§ç©æ¥æºçå±ä½ç½®ã |
| | | /// </remarks> |
| | | EndLayer, |
| | | |
| | | /// <summary> |
| | | /// ä½ä¸æä»¤ |
| | | /// </summary> |
| | | /// <remarks> |
| | | /// æ§å¶å åæºçå¨ä½ï¼ |
| | | /// - 1: å¼å§æ§è¡ä»»å¡ |
| | | /// - 2: ä»»å¡å®æ/忢 |
| | | /// </remarks> |
| | | WorkAction, |
| | | |
| | | ///// <summary> |
| | | ///// æçå· |
| | | ///// </summary> |
| | | //Barcode, |
| | | |
| | | /// <summary> |
| | | /// å½åä»»å¡å· |
| | | /// </summary> |
| | | /// <remarks> |
| | | /// å åæºå½åæ£å¨æ§è¡çä»»å¡å·ã |
| | | /// </remarks> |
| | | CurrentTaskNum |
| | | } |
| | | } |
| | |
| | | #region << ç æ¬ 注 é >> |
| | | /*---------------------------------------------------------------- |
| | | * å½å空é´ï¼WIDESEAWCS_Tasks.StackerCraneJob |
| | | * å建è
ï¼è¡ç«¥åº |
| | | * å建æ¶é´ï¼2024/8/2 16:13:36 |
| | | * çæ¬ï¼V1.0.0 |
| | | * æè¿°ï¼ |
| | | * |
| | | * ---------------------------------------------------------------- |
| | | * ä¿®æ¹äººï¼ |
| | | * ä¿®æ¹æ¶é´ï¼ |
| | | * çæ¬ï¼V1.0.1 |
| | | * ä¿®æ¹è¯´æï¼ |
| | | * |
| | | *----------------------------------------------------------------*/ |
| | | #endregion << ç æ¬ 注 é >> |
| | | |
| | | using System; |
| | | using System.Collections.Generic; |
| | | using System.Linq; |
| | | using System.Text; |
| | | using System.Threading.Tasks; |
| | | using WIDESEAWCS_Model.Models; |
| | | using WIDESEAWCS_QuartzJob.DeviceBase; |
| | | |
| | | namespace WIDESEAWCS_Tasks.StackerCraneJob |
| | | { |
| | | /// <summary> |
| | | /// å åæºä»»å¡å½ä»¤æ°æ®ç±» |
| | | /// </summary> |
| | | /// <remarks> |
| | | /// ç»§æ¿èª DeviceCommandï¼ç¨äºä¸å åæºè¿è¡ PLC éä¿¡ã |
| | | /// å
å«ä»»å¡å·ãä½ä¸ç±»åãèµ·æ¢è¡åå±åæ çåæ®µã |
| | | /// æ åå½ä»¤æ ¼å¼ï¼ç¨äºå¤§å¤æ°å··éçå åæºã |
| | | /// </remarks> |
| | | public class StackerCraneTaskCommand : DeviceCommand |
| | | { |
| | | #region <Public Menber> |
| | | /// <summary> |
| | | /// ä½ä¸å½ä»¤ |
| | | /// </summary> |
| | | /// <remarks> |
| | | /// æ§å¶å åæºçå¨ä½ï¼ |
| | | /// - 1: å¼å§æ§è¡ä»»å¡ |
| | | /// - 2: ä»»å¡å®æ/忢 |
| | | /// </remarks> |
| | | public short WorkAction { get; set; } |
| | | |
| | | /// <summary> |
| | | /// ä»»å¡å· |
| | | /// </summary> |
| | | /// <remarks> |
| | | /// WCS åé
çä»»å¡å¯ä¸æ è¯å·ã |
| | | /// </remarks> |
| | | public int TaskNum { get; set; } |
| | | |
| | | /// <summary> |
| | | /// ä½ä¸ç±»å |
| | | /// </summary> |
| | | /// <remarks> |
| | | /// æ è¯ä»»å¡çç±»åã |
| | | /// </remarks> |
| | | public short WorkType { get; set; } |
| | | |
| | | /// <summary> |
| | | /// æ æåæ®µ |
| | | /// æ æåæ®µï¼ä¿çåæ®µï¼ |
| | | /// </summary> |
| | | /// <remarks> |
| | | /// åå²éçåæ®µï¼ç®åä¸å使ç¨ã |
| | | /// </remarks> |
| | | [DataLength(6)] |
| | | public string FieldName { get; set; } = ""; |
| | | |
| | | /// <summary> |
| | | /// èµ·å§è¡ |
| | | /// </summary> |
| | | /// <remarks> |
| | | /// ä»»å¡çèµ·å§ä½ç½®-è¡åæ ï¼è´§æ¶è¡å·ï¼ã |
| | | /// å
¥åºæ¶è¡¨ç¤ºè´§ç©æ¥èªåªä¸ªä½ç½®ã |
| | | /// </remarks> |
| | | public short StartRow { get; set; } |
| | | |
| | | /// <summary> |
| | | /// èµ·å§å |
| | | /// </summary> |
| | | /// <remarks> |
| | | /// ä»»å¡çèµ·å§ä½ç½®-ååæ ï¼è´§æ¶åå·ï¼ã |
| | | /// å
¥åºæ¶è¡¨ç¤ºè´§ç©æ¥èªåªä¸ªä½ç½®ã |
| | | /// </remarks> |
| | | public short StartColumn { get; set; } |
| | | |
| | | /// <summary> |
| | | /// èµ·å§å± |
| | | /// </summary> |
| | | /// <remarks> |
| | | /// ä»»å¡çèµ·å§ä½ç½®-å±åæ ï¼è´§æ¶å±å·ï¼ã |
| | | /// å
¥åºæ¶è¡¨ç¤ºè´§ç©æ¥èªåªä¸ªä½ç½®ã |
| | | /// </remarks> |
| | | public short StartLayer { get; set; } |
| | | |
| | | /// <summary> |
| | | /// ç®æ è¡ |
| | | /// </summary> |
| | | /// <remarks> |
| | | /// ä»»å¡çç®æ ä½ç½®-è¡åæ ï¼è´§æ¶è¡å·ï¼ã |
| | | /// å
¥åºæ¶è¡¨ç¤ºè´§ç©åæ¾å°åªä¸ªä½ç½®ã |
| | | /// åºåºæ¶è¡¨ç¤ºè´§ç©ä»åªä¸ªä½ç½®ååºã |
| | | /// </remarks> |
| | | public short EndRow { get; set; } |
| | | |
| | | /// <summary> |
| | | /// ç®æ å |
| | | /// </summary> |
| | | /// <remarks> |
| | | /// ä»»å¡çç®æ ä½ç½®-ååæ ï¼è´§æ¶åå·ï¼ã |
| | | /// å
¥åºæ¶è¡¨ç¤ºè´§ç©åæ¾å°åªä¸ªä½ç½®ã |
| | | /// åºåºæ¶è¡¨ç¤ºè´§ç©ä»åªä¸ªä½ç½®ååºã |
| | | /// </remarks> |
| | | public short EndColumn { get; set; } |
| | | |
| | | /// <summary> |
| | | /// ç®æ å± |
| | | /// </summary> |
| | | /// <remarks> |
| | | /// ä»»å¡çç®æ ä½ç½®-å±åæ ï¼è´§æ¶å±å·ï¼ã |
| | | /// å
¥åºæ¶è¡¨ç¤ºè´§ç©åæ¾å°åªä¸ªä½ç½®ã |
| | | /// åºåºæ¶è¡¨ç¤ºè´§ç©ä»åªä¸ªä½ç½®ååºã |
| | | /// </remarks> |
| | | public short EndLayer { get; set; } |
| | | |
| | | #endregion <Public Menber> |
| | | } |
| | | } |
| | |
| | | using Newtonsoft.Json; |
| | | using Newtonsoft.Json; |
| | | using System.Diagnostics.CodeAnalysis; |
| | | using WIDESEA_Core; |
| | | using WIDESEAWCS_Common.HttpEnum; |
| | |
| | | namespace WIDESEAWCS_Tasks |
| | | { |
| | | /// <summary> |
| | | /// å åæºä»»å¡éæ©å¨ï¼å°è£
任塿éä¸ç«å°å¯ç¨æ§å¤æã |
| | | /// å åæºä»»å¡éæ©å¨ - å°è£
任塿éä¸ç«å°å¯ç¨æ§å¤æ |
| | | /// </summary> |
| | | /// <remarks> |
| | | /// æ ¸å¿èè´£ï¼ |
| | | /// 1. æ ¹æ®å åæºä¸ä¸ä»»å¡ç±»åéæ©ä¸ä¸ä¸ªåéçä»»å¡ |
| | | /// 2. 对åºåºä»»å¡è¿è¡ç§»åºæ£æ¥ï¼WMS å¤æï¼ |
| | | /// 3. 夿åºåºç«å°æ¯å¦å¯ç¨ï¼æ¯å¦è¢«å ç¨ï¼ |
| | | /// 4. å°è¯éæ©å¤éåºåºç«å° |
| | | /// |
| | | /// ä»»å¡éæ©çç¥ï¼ |
| | | /// - 妿ä¸ä¸ä»»å¡æ¯åºåºï¼ä¼å
éæ©å
¥åºä»»å¡ |
| | | /// - 妿ä¸ä¸ä»»å¡æ¯å
¥åºï¼ä¼å
éæ©åºåºä»»å¡ |
| | | /// - 对äºåºåºä»»å¡ï¼å
æ£æ¥æ¯å¦éè¦ç§»åº |
| | | /// </remarks> |
| | | public class StackerCraneTaskSelector |
| | | { |
| | | /// <summary> |
| | | /// ä»»å¡æå¡ |
| | | /// </summary> |
| | | private readonly ITaskService _taskService; |
| | | |
| | | /// <summary> |
| | | /// è·¯ç±æå¡ |
| | | /// </summary> |
| | | private readonly IRouterService _routerService; |
| | | |
| | | /// <summary> |
| | | /// ç§»åºæ£æ¥å§æå½æ° |
| | | /// </summary> |
| | | /// <remarks> |
| | | /// ç¨äºè°ç¨ WMS 夿åºåºä»»å¡æ¯å¦éè¦å
æ§è¡ç§»åºã |
| | | /// </remarks> |
| | | private readonly Func<int, Dt_Task?> _transferCheck; |
| | | |
| | | /// <summary> |
| | | /// æé 彿°ï¼ä½¿ç¨ HTTP 客æ·ç«¯å¸®å©ç±»ï¼ |
| | | /// </summary> |
| | | /// <param name="taskService">任塿å¡</param> |
| | | /// <param name="routerService">è·¯ç±æå¡</param> |
| | | /// <param name="httpClientHelper">HTTP 客æ·ç«¯å¸®å©ç±»</param> |
| | | public StackerCraneTaskSelector(ITaskService taskService, IRouterService routerService, HttpClientHelper httpClientHelper) |
| | | : this(taskService, routerService, taskNum => QueryTransferTask(httpClientHelper, taskNum)) |
| | | { |
| | | } |
| | | |
| | | /// <summary> |
| | | /// æé 彿°ï¼ä½¿ç¨å§æå½æ°ï¼ |
| | | /// </summary> |
| | | /// <param name="taskService">任塿å¡</param> |
| | | /// <param name="routerService">è·¯ç±æå¡</param> |
| | | /// <param name="transferCheck">ç§»åºæ£æ¥å½æ°</param> |
| | | public StackerCraneTaskSelector(ITaskService taskService, IRouterService routerService, Func<int, Dt_Task?> transferCheck) |
| | | { |
| | | _taskService = taskService; |
| | |
| | | _transferCheck = transferCheck; |
| | | } |
| | | |
| | | /// <summary> |
| | | /// éæ©åéçä»»å¡ |
| | | /// </summary> |
| | | /// <remarks> |
| | | /// æ ¹æ®å åæºçä¸ä¸ä»»å¡ç±»ååå½åç¶æï¼éæ©ä¸ä¸ä¸ªåºè¯¥æ§è¡çä»»å¡ã |
| | | /// |
| | | /// éæ©çç¥ï¼ |
| | | /// 1. å¦ææ²¡æä¸ä¸ä»»å¡ç±»åï¼æ¥è¯¢æ®éä»»å¡ |
| | | /// 2. 妿ä¸ä¸ä»»å¡æ¯åºåºï¼ä¼å
æ¥å
¥åºä»»å¡ï¼åæ¥åºåºä»»å¡ |
| | | /// 3. 妿ä¸ä¸ä»»å¡æ¯å
¥åºï¼ä¼å
æ¥åºåºä»»å¡ |
| | | /// 4. 对äºåºåºä»»å¡ï¼éè¦å¤æç«å°æ¯å¦å¯ç¨ |
| | | /// </remarks> |
| | | /// <param name="commonStackerCrane">å åæºè®¾å¤å¯¹è±¡</param> |
| | | /// <returns>éä¸çä»»å¡ï¼å¦ææ²¡æå¯ç¨ä»»å¡è¿å null</returns> |
| | | public Dt_Task? SelectTask(IStackerCrane commonStackerCrane) |
| | | { |
| | | Dt_Task? candidateTask; |
| | | |
| | | // æ ¹æ®ä¸ä¸ä»»å¡ç±»åå³å®æ¥è¯¢çç¥ |
| | | if (commonStackerCrane.LastTaskType == null) |
| | | { |
| | | // 没æä¸ä¸ä»»å¡ç±»åï¼æ¥è¯¢æ®éä»»å¡ |
| | | candidateTask = _taskService.QueryStackerCraneTask(commonStackerCrane.DeviceCode); |
| | | } |
| | | else if (commonStackerCrane.LastTaskType.GetValueOrDefault().GetTaskTypeGroup() == TaskTypeGroup.OutbondGroup) |
| | | { |
| | | // ä¸ä¸ä»»å¡æ¯åºåºï¼ä¼å
æ¥å
¥åºä»»å¡ |
| | | candidateTask = _taskService.QueryStackerCraneInTask(commonStackerCrane.DeviceCode); |
| | | // å¦ææ²¡æå
¥åºä»»å¡ï¼åæ¥ä¸ä¸åºåºä»»å¡ |
| | | candidateTask ??= _taskService.QueryStackerCraneOutTask(commonStackerCrane.DeviceCode); |
| | | } |
| | | else |
| | | { |
| | | // ä¸ä¸ä»»å¡æ¯å
¥åºï¼éåºåºï¼ï¼ä¼å
æ¥åºåºä»»å¡ |
| | | candidateTask = _taskService.QueryStackerCraneOutTask(commonStackerCrane.DeviceCode); |
| | | } |
| | | |
| | | // å¦ææ²¡æåéä»»å¡ï¼è¿å null |
| | | if (candidateTask == null) |
| | | { |
| | | return null; |
| | | } |
| | | |
| | | // 妿䏿¯åºåºä»»å¡ï¼ç´æ¥è¿å |
| | | if (candidateTask.TaskType.GetTaskTypeGroup() != TaskTypeGroup.OutbondGroup) |
| | | { |
| | | return candidateTask; |
| | | } |
| | | |
| | | // å°è¯éæ©åºåºä»»å¡ï¼å¯è½éè¦ç§»åºæ£æ¥åç«å°å¯ç¨æ§å¤æï¼ |
| | | Dt_Task? selectedTask = TrySelectOutboundTask(candidateTask); |
| | | if (selectedTask != null) |
| | | { |
| | | return selectedTask; |
| | | } |
| | | |
| | | // æ¥æ¾å
¶ä»å¯ç¨çåºåºç«å° |
| | | var otherOutStationCodes = _routerService |
| | | .QueryNextRoutes(commonStackerCrane.DeviceCode, candidateTask.NextAddress, candidateTask.TaskType) |
| | | .Select(x => x.ChildPosi) |
| | | .ToList(); |
| | | |
| | | // æ¥è¯¢å
¶ä»ç«å°çåºåºä»»å¡ |
| | | var tasks = _taskService.QueryStackerCraneOutTasks(commonStackerCrane.DeviceCode, otherOutStationCodes); |
| | | foreach (var alternativeTask in tasks) |
| | | { |
| | |
| | | } |
| | | } |
| | | |
| | | // 没æå¯ç¨åºåºä»»å¡ï¼å°è¯è¿åå
¥åºä»»å¡ |
| | | return _taskService.QueryStackerCraneInTask(commonStackerCrane.DeviceCode); |
| | | } |
| | | |
| | | /// <summary> |
| | | /// å°è¯éæ©åºåºä»»å¡ |
| | | /// </summary> |
| | | /// <remarks> |
| | | /// 对åéåºåºä»»å¡è¿è¡ï¼ |
| | | /// 1. ç§»åºæ£æ¥ï¼è°ç¨ WMS 夿æ¯å¦éè¦ç§»åºï¼ |
| | | /// 2. ç«å°å¯ç¨æ§å¤æ |
| | | /// |
| | | /// 妿任å¡è¢«å¤å®ä¸ºéè¦ç§»åºï¼åè¿åç§»åºåçä»»å¡ã |
| | | /// </remarks> |
| | | /// <param name="outboundTask">åéåºåºä»»å¡</param> |
| | | /// <returns>å¯éä¸çä»»å¡ï¼æ nullï¼ç«å°ä¸å¯ç¨ï¼</returns> |
| | | private Dt_Task? TrySelectOutboundTask(Dt_Task outboundTask) |
| | | { |
| | | // åªè¦æ¯åºåºä»»å¡ï¼å¿
é¡»å
è°ç¨WMS夿æ¯å¦éè¦ç§»åºã |
| | | // å¯¹äºææåºåºä»»å¡ï¼å¿
é¡»å
è°ç¨ WMS 夿æ¯å¦éè¦ç§»åº |
| | | var taskAfterTransferCheck = _transferCheck(outboundTask.TaskNum) ?? outboundTask; |
| | | var taskGroup = taskAfterTransferCheck.TaskType.GetTaskTypeGroup(); |
| | | |
| | | // 妿æ¯ç§»åºä»»å¡æåºåºä»»å¡ï¼å°è¯ä» WMS æ·»å ä»»å¡ |
| | | if (taskGroup == TaskTypeGroup.RelocationGroup || taskGroup == TaskTypeGroup.OutbondGroup) |
| | | { |
| | | TryAddTaskFromWms(taskAfterTransferCheck); |
| | | } |
| | | |
| | | // 妿æ¯ç§»åºä»»å¡ï¼ç´æ¥è¿å |
| | | if (taskGroup == TaskTypeGroup.RelocationGroup) |
| | | { |
| | | return taskAfterTransferCheck; |
| | | } |
| | | |
| | | // 妿䏿¯åºåºä»»å¡ï¼è¿ååä»»å¡ |
| | | if (taskGroup != TaskTypeGroup.OutbondGroup) |
| | | { |
| | | return taskAfterTransferCheck; |
| | | } |
| | | |
| | | // 夿åºåºç«å°æ¯å¦å¯ç¨ |
| | | return IsOutTaskStationAvailable(taskAfterTransferCheck) ? taskAfterTransferCheck : null; |
| | | } |
| | | |
| | | /// <summary> |
| | | /// è°ç¨ WMS æ£æ¥ç§»åº |
| | | /// </summary> |
| | | /// <remarks> |
| | | /// éè¿ HTTP 请æ±è°ç¨ WMS çç§»åºæ£æ¥æ¥å£ã |
| | | /// </remarks> |
| | | /// <param name="httpClientHelper">HTTP 客æ·ç«¯å¸®å©ç±»</param> |
| | | /// <param name="taskNum">ä»»å¡å·</param> |
| | | /// <returns>妿éè¦ç§»åºè¿åç§»åºä»»å¡ï¼å¦åè¿å null</returns> |
| | | private static Dt_Task? QueryTransferTask(HttpClientHelper httpClientHelper, int taskNum) |
| | | { |
| | | // è°ç¨ WMS çç§»åºæ£æ¥æ¥å£ |
| | | var response = httpClientHelper.Post<WebResponseContent>( |
| | | nameof(ConfigKey.TransferCheck), |
| | | taskNum.ToString()); |
| | | |
| | | // æ£æ¥ååºæ¯å¦æå |
| | | if (response == null || !response.IsSuccess || response.Data == null || !response.Data.Status || response.Data.Data == null) |
| | | { |
| | | return null; |
| | | } |
| | | |
| | | // è§£æè¿åç任塿°æ® |
| | | var taskJson = response.Data.Data.ToString(); |
| | | return string.IsNullOrWhiteSpace(taskJson) ? null : JsonConvert.DeserializeObject<Dt_Task>(taskJson); |
| | | } |
| | | |
| | | /// <summary> |
| | | /// å°è¯ä» WMS æ·»å ä»»å¡ |
| | | /// </summary> |
| | | /// <remarks> |
| | | /// 妿任å¡ä¸åå¨äºæ¬å°æ°æ®åºï¼ä» WMS è¿åçæ°æ®æ·»å å°æ¬å°ã |
| | | /// </remarks> |
| | | /// <param name="task">ä»»å¡å¯¹è±¡</param> |
| | | private void TryAddTaskFromWms(Dt_Task task) |
| | | { |
| | | // æ£æ¥ä»»å¡å·æ¯å¦ææ |
| | | if (task.TaskNum <= 0) |
| | | { |
| | | return; |
| | | } |
| | | |
| | | // æ£æ¥ä»»å¡æ¯å¦å·²åå¨ |
| | | var existingTask = _taskService.QueryByTaskNum(task.TaskNum); |
| | | if (existingTask != null) |
| | | { |
| | | return; |
| | | } |
| | | |
| | | // æ·»å å°æ¬å°æ°æ®åº |
| | | _taskService.AddData(task); |
| | | } |
| | | |
| | | /// <summary> |
| | | /// 夿åºåºç«å°æ¯å¦å¯ç¨ |
| | | /// </summary> |
| | | /// <remarks> |
| | | /// æ£æ¥ç®æ ç«å°å¯¹åºçè¾é线æ¯å¦è¢«å ç¨ã |
| | | /// 妿ç«å°ä¸æè´§ç©ï¼å该ç«å°ä¸å¯ç¨ã |
| | | /// </remarks> |
| | | /// <param name="task">åºåºä»»å¡</param> |
| | | /// <returns>ç«å°å¯ç¨è¿å true</returns> |
| | | private bool IsOutTaskStationAvailable([NotNull] Dt_Task task) |
| | | { |
| | | // ç¡®å®ä»»å¡ç±»å |
| | | int taskType = 0; |
| | | if (task.TaskType == (int)TaskOutboundTypeEnum.OutEmpty) |
| | | { |
| | | // 空æçåºåº |
| | | taskType = 100; |
| | | } |
| | | else |
| | | taskType = task.TaskType; |
| | | |
| | | // æ¥è¯¢ç«å°è·¯ç±ä¿¡æ¯ |
| | | Dt_Router? router = _routerService.QueryNextRoute(task.Roadway, task.NextAddress, taskType); |
| | | if (router == null) |
| | | { |
| | | // æªæ¾å°ç«å°è·¯ç±ä¿¡æ¯ |
| | | _taskService.UpdateTaskExceptionMessage(task.TaskNum, $"æªæ¾å°ç«å°ã{task.NextAddress}ãä¿¡æ¯ï¼æ æ³æ ¡éªç«å°"); |
| | | return false; |
| | | } |
| | | |
| | | // æ¥æ¾ç«å°å¯¹åºçè®¾å¤ |
| | | IDevice? device = Storage.Devices.FirstOrDefault(x => x.DeviceCode == router.ChildPosiDeviceCode); |
| | | if (device == null) |
| | | { |
| | | // æªæ¾å°è®¾å¤ |
| | | _taskService.UpdateTaskExceptionMessage(task.TaskNum, $"æªæ¾å°åºåºç«å°ã{router.ChildPosiDeviceCode}ã对åºçéè®¯å¯¹è±¡ï¼æ æ³å¤æåºåºç«å°æ¯å¦è¢«å ç¨"); |
| | | return false; |
| | | } |
| | | |
| | | // 转æ¢ä¸ºè¾éçº¿è®¾å¤ |
| | | CommonConveyorLine conveyorLine = (CommonConveyorLine)device; |
| | | |
| | | // æ£æ¥ç«å°æ¯å¦è¢«å ç¨ |
| | | return conveyorLine.IsOccupied(router.ChildPosi); |
| | | } |
| | | } |
| | | } |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | { |
| | | "permissions": { |
| | | "allow": [ |
| | | "Bash(git:*)", |
| | | "Bash(dotnet build:*)" |
| | | ] |
| | | } |
| | | } |
| | |
| | | { |
| | | "version": "1.0.0", |
| | | "lastScanned": 1774324348368, |
| | | "lastScanned": 1774489415859, |
| | | "projectRoot": "d:\\Git\\ShanMeiXinNengYuan\\Code\\WMS\\WIDESEA_WMSClient", |
| | | "techStack": { |
| | | "languages": [ |
| | |
| | | "category": "build" |
| | | } |
| | | ], |
| | | "packageManager": "yarn", |
| | | "packageManager": "pnpm", |
| | | "runtime": null |
| | | }, |
| | | "build": { |
| | | "buildCommand": "yarn build", |
| | | "buildCommand": "pnpm build", |
| | | "testCommand": null, |
| | | "lintCommand": "yarn lint", |
| | | "devCommand": "yarn dev", |
| | | "lintCommand": "pnpm lint", |
| | | "devCommand": null, |
| | | "scripts": { |
| | | "dev": "vite", |
| | | "serve": "vite", |
| | | "build": "vite build", |
| | | "preview": "vite preview --port 8080", |
| | | "test:unit": "vue-cli-service test:unit", |
| | |
| | | "path": "config", |
| | | "purpose": "Configuration files", |
| | | "fileCount": 1, |
| | | "lastAccessed": 1774324348233, |
| | | "lastAccessed": 1774489415781, |
| | | "keyFiles": [ |
| | | "buttons.js" |
| | | ] |
| | |
| | | "path": "dist", |
| | | "purpose": "Distribution/build output", |
| | | "fileCount": 4, |
| | | "lastAccessed": 1774324348234, |
| | | "lastAccessed": 1774489415782, |
| | | "keyFiles": [ |
| | | "index.html", |
| | | "wcslogo.png", |
| | |
| | | "path": "public", |
| | | "purpose": "Public files", |
| | | "fileCount": 4, |
| | | "lastAccessed": 1774324348294, |
| | | "lastAccessed": 1774489415810, |
| | | "keyFiles": [ |
| | | "index.html", |
| | | "wcslogo.png", |
| | |
| | | "path": "src", |
| | | "purpose": "Source code", |
| | | "fileCount": 2, |
| | | "lastAccessed": 1774324348294, |
| | | "lastAccessed": 1774489415810, |
| | | "keyFiles": [ |
| | | "App.vue", |
| | | "main.js" |
| | |
| | | "path": "tests", |
| | | "purpose": "Test files", |
| | | "fileCount": 0, |
| | | "lastAccessed": 1774324348294, |
| | | "lastAccessed": 1774489415811, |
| | | "keyFiles": [] |
| | | }, |
| | | "dist\\assets": { |
| | | "path": "dist\\assets", |
| | | "purpose": "Static assets", |
| | | "fileCount": 106, |
| | | "lastAccessed": 1774324348296, |
| | | "fileCount": 107, |
| | | "lastAccessed": 1774489415814, |
| | | "keyFiles": [ |
| | | "401-CX5beHYt.js", |
| | | "404-mamt5IUf.js", |
| | | "Audit-BmPdFI9f.js" |
| | | "401-cNgsEGiV.js", |
| | | "404-CZEj1mZh.js", |
| | | "Audit-C52MvHzW.css" |
| | | ] |
| | | }, |
| | | "dist\\static": { |
| | | "path": "dist\\static", |
| | | "purpose": "Static files", |
| | | "fileCount": 1, |
| | | "lastAccessed": 1774324348296, |
| | | "lastAccessed": 1774489415815, |
| | | "keyFiles": [ |
| | | "login_bg.png" |
| | | ] |
| | |
| | | "path": "public\\static", |
| | | "purpose": "Static files", |
| | | "fileCount": 1, |
| | | "lastAccessed": 1774324348297, |
| | | "lastAccessed": 1774489415815, |
| | | "keyFiles": [ |
| | | "login_bg.png" |
| | | ] |
| | |
| | | "path": "src\\api", |
| | | "purpose": "API routes", |
| | | "fileCount": 3, |
| | | "lastAccessed": 1774324348297, |
| | | "lastAccessed": 1774489415816, |
| | | "keyFiles": [ |
| | | "http.js", |
| | | "permission.js", |
| | |
| | | "path": "src\\assets", |
| | | "purpose": "Static assets", |
| | | "fileCount": 1, |
| | | "lastAccessed": 1774324348298, |
| | | "lastAccessed": 1774489415817, |
| | | "keyFiles": [ |
| | | "logo.png" |
| | | ] |
| | |
| | | "path": "src\\components", |
| | | "purpose": "UI components", |
| | | "fileCount": 0, |
| | | "lastAccessed": 1774324348299, |
| | | "lastAccessed": 1774489415817, |
| | | "keyFiles": [] |
| | | }, |
| | | "src\\views": { |
| | | "path": "src\\views", |
| | | "purpose": "View templates", |
| | | "fileCount": 3, |
| | | "lastAccessed": 1774324348299, |
| | | "lastAccessed": 1774489415818, |
| | | "keyFiles": [ |
| | | "Home.vue", |
| | | "Index.vue", |
| | |
| | | "WorkspaceRootPath": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WMS\\WIDESEA_WMSServer\\", |
| | | "Documents": [ |
| | | { |
| | | "AbsoluteMoniker": "D:0:0:{D81A65B5-47D1-40C1-8FDE-7D24FF003F51}|WIDESEA_WMSServer\\WIDESEA_WMSServer.csproj|d:\\git\\shanmeixinnengyuan\\code\\wms\\widesea_wmsserver\\widesea_wmsserver\\backgroundservices\\autooutboundtaskbackgroundservice.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}", |
| | | "RelativeMoniker": "D:0:0:{D81A65B5-47D1-40C1-8FDE-7D24FF003F51}|WIDESEA_WMSServer\\WIDESEA_WMSServer.csproj|solutionrelative:widesea_wmsserver\\backgroundservices\\autooutboundtaskbackgroundservice.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}" |
| | | }, |
| | | { |
| | | "AbsoluteMoniker": "D:0:0:{7DC26D42-D8EE-46F0-BA66-A13457086885}|WIDESEA_StockService\\WIDESEA_StockService.csproj|d:\\git\\shanmeixinnengyuan\\code\\wms\\widesea_wmsserver\\widesea_stockservice\\stockserivce.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}", |
| | | "RelativeMoniker": "D:0:0:{7DC26D42-D8EE-46F0-BA66-A13457086885}|WIDESEA_StockService\\WIDESEA_StockService.csproj|solutionrelative:widesea_stockservice\\stockserivce.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}" |
| | | }, |
| | | { |
| | | "AbsoluteMoniker": "D:0:0:{7DC26D42-D8EE-46F0-BA66-A13457086885}|WIDESEA_StockService\\WIDESEA_StockService.csproj|d:\\git\\shanmeixinnengyuan\\code\\wms\\widesea_wmsserver\\widesea_stockservice\\stockinfoservice.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}", |
| | | "RelativeMoniker": "D:0:0:{7DC26D42-D8EE-46F0-BA66-A13457086885}|WIDESEA_StockService\\WIDESEA_StockService.csproj|solutionrelative:widesea_stockservice\\stockinfoservice.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}" |
| | | }, |
| | | { |
| | | "AbsoluteMoniker": "D:0:0:{7D7534D4-51D9-46DC-A6B7-6430042F4E12}|WIDESEA_TaskInfoService\\WIDESEA_TaskInfoService.csproj|d:\\git\\shanmeixinnengyuan\\code\\wms\\widesea_wmsserver\\widesea_taskinfoservice\\taskservice.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}", |
| | | "RelativeMoniker": "D:0:0:{7D7534D4-51D9-46DC-A6B7-6430042F4E12}|WIDESEA_TaskInfoService\\WIDESEA_TaskInfoService.csproj|solutionrelative:widesea_taskinfoservice\\taskservice.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}" |
| | | }, |
| | | { |
| | | "AbsoluteMoniker": "D:0:0:{929DF936-042C-4EEC-8722-A831FC2F0AEA}|WIDESEA_DTO\\WIDESEA_DTO.csproj|d:\\git\\shanmeixinnengyuan\\code\\wms\\widesea_wmsserver\\widesea_dto\\task\\wmstaskdto.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}", |
| | | "RelativeMoniker": "D:0:0:{929DF936-042C-4EEC-8722-A831FC2F0AEA}|WIDESEA_DTO\\WIDESEA_DTO.csproj|solutionrelative:widesea_dto\\task\\wmstaskdto.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}" |
| | | }, |
| | | { |
| | | "AbsoluteMoniker": "D:0:0:{D81A65B5-47D1-40C1-8FDE-7D24FF003F51}|WIDESEA_WMSServer\\WIDESEA_WMSServer.csproj|d:\\git\\shanmeixinnengyuan\\code\\wms\\widesea_wmsserver\\widesea_wmsserver\\controllers\\taskinfo\\taskcontroller.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}", |
| | | "RelativeMoniker": "D:0:0:{D81A65B5-47D1-40C1-8FDE-7D24FF003F51}|WIDESEA_WMSServer\\WIDESEA_WMSServer.csproj|solutionrelative:widesea_wmsserver\\controllers\\taskinfo\\taskcontroller.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}" |
| | | }, |
| | | { |
| | | "AbsoluteMoniker": "D:0:0:{AF8F3D65-1D75-4B8F-AFD9-4150E591C44D}|WIDESEA_Common\\WIDESEA_Common.csproj|d:\\git\\shanmeixinnengyuan\\code\\wms\\widesea_wmsserver\\widesea_common\\taskenum\\tasktypeenum.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}", |
| | | "RelativeMoniker": "D:0:0:{AF8F3D65-1D75-4B8F-AFD9-4150E591C44D}|WIDESEA_Common\\WIDESEA_Common.csproj|solutionrelative:widesea_common\\taskenum\\tasktypeenum.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}" |
| | | }, |
| | | { |
| | | "AbsoluteMoniker": "D:0:0:{AF8F3D65-1D75-4B8F-AFD9-4150E591C44D}|WIDESEA_Common\\WIDESEA_Common.csproj|d:\\git\\shanmeixinnengyuan\\code\\wms\\widesea_wmsserver\\widesea_common\\stockenum\\stockstatusemun.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}", |
| | | "RelativeMoniker": "D:0:0:{AF8F3D65-1D75-4B8F-AFD9-4150E591C44D}|WIDESEA_Common\\WIDESEA_Common.csproj|solutionrelative:widesea_common\\stockenum\\stockstatusemun.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}" |
| | | }, |
| | | { |
| | | "AbsoluteMoniker": "D:0:0:{D11C804C-2FF4-4C18-A3EE-2F0574427BB3}|WIDESEA_BasicService\\WIDESEA_BasicService.csproj|d:\\git\\shanmeixinnengyuan\\code\\wms\\widesea_wmsserver\\widesea_basicservice\\locationinfoservice.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}", |
| | | "RelativeMoniker": "D:0:0:{D11C804C-2FF4-4C18-A3EE-2F0574427BB3}|WIDESEA_BasicService\\WIDESEA_BasicService.csproj|solutionrelative:widesea_basicservice\\locationinfoservice.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}" |
| | | }, |
| | | { |
| | | "AbsoluteMoniker": "D:0:0:{929DF936-042C-4EEC-8722-A831FC2F0AEA}|WIDESEA_DTO\\WIDESEA_DTO.csproj|d:\\git\\shanmeixinnengyuan\\code\\wms\\widesea_wmsserver\\widesea_dto\\stock\\stockdto.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}", |
| | | "RelativeMoniker": "D:0:0:{929DF936-042C-4EEC-8722-A831FC2F0AEA}|WIDESEA_DTO\\WIDESEA_DTO.csproj|solutionrelative:widesea_dto\\stock\\stockdto.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}" |
| | | }, |
| | | { |
| | | "AbsoluteMoniker": "D:0:0:{CE0DB91F-5A68-448E-A419-4C26B5039F51}|WIDESEA_ITaskInfoService\\WIDESEA_ITaskInfoService.csproj|d:\\git\\shanmeixinnengyuan\\code\\wms\\widesea_wmsserver\\widesea_itaskinfoservice\\itaskservice.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}", |
| | | "RelativeMoniker": "D:0:0:{CE0DB91F-5A68-448E-A419-4C26B5039F51}|WIDESEA_ITaskInfoService\\WIDESEA_ITaskInfoService.csproj|solutionrelative:widesea_itaskinfoservice\\itaskservice.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}" |
| | | }, |
| | | { |
| | | "AbsoluteMoniker": "D:0:0:{AF8F3D65-1D75-4B8F-AFD9-4150E591C44D}|WIDESEA_Common\\WIDESEA_Common.csproj|d:\\git\\shanmeixinnengyuan\\code\\wms\\widesea_wmsserver\\widesea_common\\taskenum\\taskstatusenum.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}", |
| | | "RelativeMoniker": "D:0:0:{AF8F3D65-1D75-4B8F-AFD9-4150E591C44D}|WIDESEA_Common\\WIDESEA_Common.csproj|solutionrelative:widesea_common\\taskenum\\taskstatusenum.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}" |
| | | }, |
| | | { |
| | | "AbsoluteMoniker": "D:0:0:{D81A65B5-47D1-40C1-8FDE-7D24FF003F51}|WIDESEA_WMSServer\\WIDESEA_WMSServer.csproj|d:\\git\\shanmeixinnengyuan\\code\\wms\\widesea_wmsserver\\widesea_wmsserver\\appsettings.json||{90A6B3A7-C1A3-4009-A288-E2FF89E96FA0}", |
| | | "RelativeMoniker": "D:0:0:{D81A65B5-47D1-40C1-8FDE-7D24FF003F51}|WIDESEA_WMSServer\\WIDESEA_WMSServer.csproj|solutionrelative:widesea_wmsserver\\appsettings.json||{90A6B3A7-C1A3-4009-A288-E2FF89E96FA0}" |
| | | }, |
| | |
| | | "RelativeMoniker": "D:0:0:{D81A65B5-47D1-40C1-8FDE-7D24FF003F51}|WIDESEA_WMSServer\\WIDESEA_WMSServer.csproj|solutionrelative:widesea_wmsserver\\program.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}" |
| | | }, |
| | | { |
| | | "AbsoluteMoniker": "D:0:0:{D81A65B5-47D1-40C1-8FDE-7D24FF003F51}|WIDESEA_WMSServer\\WIDESEA_WMSServer.csproj|d:\\git\\shanmeixinnengyuan\\code\\wms\\widesea_wmsserver\\widesea_wmsserver\\controllers\\basic\\locationinfocontroller.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}", |
| | | "RelativeMoniker": "D:0:0:{D81A65B5-47D1-40C1-8FDE-7D24FF003F51}|WIDESEA_WMSServer\\WIDESEA_WMSServer.csproj|solutionrelative:widesea_wmsserver\\controllers\\basic\\locationinfocontroller.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}" |
| | | "AbsoluteMoniker": "D:0:0:{111BD7AA-9749-4506-9772-79F9EF14754C}|WIDESEA_Core\\WIDESEA_Core.csproj|d:\\git\\shanmeixinnengyuan\\code\\wms\\widesea_wmsserver\\widesea_core\\baseservices\\servicebase.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}", |
| | | "RelativeMoniker": "D:0:0:{111BD7AA-9749-4506-9772-79F9EF14754C}|WIDESEA_Core\\WIDESEA_Core.csproj|solutionrelative:widesea_core\\baseservices\\servicebase.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}" |
| | | } |
| | | ], |
| | | "DocumentGroupContainers": [ |
| | |
| | | "DocumentGroups": [ |
| | | { |
| | | "DockedWidth": 200, |
| | | "SelectedChildIndex": 8, |
| | | "SelectedChildIndex": 4, |
| | | "Children": [ |
| | | { |
| | | "$type": "Bookmark", |
| | |
| | | }, |
| | | { |
| | | "$type": "Document", |
| | | "DocumentIndex": 4, |
| | | "Title": "WMSTaskDTO.cs", |
| | | "DocumentMoniker": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WMS\\WIDESEA_WMSServer\\WIDESEA_DTO\\Task\\WMSTaskDTO.cs", |
| | | "RelativeDocumentMoniker": "WIDESEA_DTO\\Task\\WMSTaskDTO.cs", |
| | | "ToolTip": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WMS\\WIDESEA_WMSServer\\WIDESEA_DTO\\Task\\WMSTaskDTO.cs", |
| | | "RelativeToolTip": "WIDESEA_DTO\\Task\\WMSTaskDTO.cs", |
| | | "ViewState": "AgIAABgAAAAAAAAAAAAIwCkAAAAdAAAAAAAAAA==", |
| | | "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|", |
| | | "WhenOpened": "2026-03-17T07:42:09.48Z" |
| | | }, |
| | | { |
| | | "$type": "Document", |
| | | "DocumentIndex": 9, |
| | | "Title": "StockDTO.cs", |
| | | "DocumentMoniker": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WMS\\WIDESEA_WMSServer\\WIDESEA_DTO\\Stock\\StockDTO.cs", |
| | | "RelativeDocumentMoniker": "WIDESEA_DTO\\Stock\\StockDTO.cs", |
| | | "ToolTip": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WMS\\WIDESEA_WMSServer\\WIDESEA_DTO\\Stock\\StockDTO.cs", |
| | | "RelativeToolTip": "WIDESEA_DTO\\Stock\\StockDTO.cs", |
| | | "ViewState": "AgIAAA8AAAAAAAAAAAAIwAoAAAA+AAAAAAAAAA==", |
| | | "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|", |
| | | "WhenOpened": "2026-03-17T03:01:04.659Z" |
| | | }, |
| | | { |
| | | "$type": "Document", |
| | | "DocumentIndex": 10, |
| | | "Title": "ITaskService.cs", |
| | | "DocumentMoniker": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WMS\\WIDESEA_WMSServer\\WIDESEA_ITaskInfoService\\ITaskService.cs", |
| | | "RelativeDocumentMoniker": "WIDESEA_ITaskInfoService\\ITaskService.cs", |
| | | "ToolTip": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WMS\\WIDESEA_WMSServer\\WIDESEA_ITaskInfoService\\ITaskService.cs", |
| | | "RelativeToolTip": "WIDESEA_ITaskInfoService\\ITaskService.cs", |
| | | "ViewState": "AgIAAIIAAAAAAAAAAAAMwIkAAAAVAAAAAAAAAA==", |
| | | "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|", |
| | | "WhenOpened": "2026-03-17T03:12:58.977Z" |
| | | }, |
| | | { |
| | | "$type": "Document", |
| | | "DocumentIndex": 6, |
| | | "Title": "TaskTypeEnum.cs", |
| | | "DocumentMoniker": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WMS\\WIDESEA_WMSServer\\WIDESEA_Common\\TaskEnum\\TaskTypeEnum.cs", |
| | | "RelativeDocumentMoniker": "WIDESEA_Common\\TaskEnum\\TaskTypeEnum.cs", |
| | | "ToolTip": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WMS\\WIDESEA_WMSServer\\WIDESEA_Common\\TaskEnum\\TaskTypeEnum.cs", |
| | | "RelativeToolTip": "WIDESEA_Common\\TaskEnum\\TaskTypeEnum.cs", |
| | | "ViewState": "AgIAAIsAAAAAAAAAAAAewKAAAAAIAAAAAAAAAA==", |
| | | "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|", |
| | | "WhenOpened": "2026-03-17T02:28:48.033Z" |
| | | }, |
| | | { |
| | | "$type": "Document", |
| | | "DocumentIndex": 5, |
| | | "Title": "TaskController.cs", |
| | | "DocumentMoniker": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WMS\\WIDESEA_WMSServer\\WIDESEA_WMSServer\\Controllers\\TaskInfo\\TaskController.cs", |
| | | "RelativeDocumentMoniker": "WIDESEA_WMSServer\\Controllers\\TaskInfo\\TaskController.cs", |
| | | "ToolTip": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WMS\\WIDESEA_WMSServer\\WIDESEA_WMSServer\\Controllers\\TaskInfo\\TaskController.cs", |
| | | "RelativeToolTip": "WIDESEA_WMSServer\\Controllers\\TaskInfo\\TaskController.cs", |
| | | "ViewState": "AgIAAIoAAAAAAAAAAAAhwJsAAAAIAAAAAAAAAA==", |
| | | "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|", |
| | | "WhenOpened": "2026-03-13T02:00:31.089Z" |
| | | }, |
| | | { |
| | | "$type": "Document", |
| | | "DocumentIndex": 0, |
| | | "Title": "AutoOutboundTaskBackgroundService.cs", |
| | | "DocumentMoniker": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WMS\\WIDESEA_WMSServer\\WIDESEA_WMSServer\\BackgroundServices\\AutoOutboundTaskBackgroundService.cs", |
| | | "RelativeDocumentMoniker": "WIDESEA_WMSServer\\BackgroundServices\\AutoOutboundTaskBackgroundService.cs", |
| | | "ToolTip": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WMS\\WIDESEA_WMSServer\\WIDESEA_WMSServer\\BackgroundServices\\AutoOutboundTaskBackgroundService.cs", |
| | | "RelativeToolTip": "WIDESEA_WMSServer\\BackgroundServices\\AutoOutboundTaskBackgroundService.cs", |
| | | "ViewState": "AgIAABQAAAAAAAAAAADwvykAAABdAAAAAAAAAA==", |
| | | "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|", |
| | | "WhenOpened": "2026-03-12T10:18:13.91Z", |
| | | "EditorCaption": "" |
| | | }, |
| | | { |
| | | "$type": "Document", |
| | | "DocumentIndex": 12, |
| | | "Title": "appsettings.json", |
| | | "DocumentMoniker": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WMS\\WIDESEA_WMSServer\\WIDESEA_WMSServer\\appsettings.json", |
| | | "RelativeDocumentMoniker": "WIDESEA_WMSServer\\appsettings.json", |
| | | "ToolTip": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WMS\\WIDESEA_WMSServer\\WIDESEA_WMSServer\\appsettings.json", |
| | | "RelativeToolTip": "WIDESEA_WMSServer\\appsettings.json", |
| | | "ViewState": "AgIAAAAAAAAAAAAAAAAAABgAAAA9AAAAAAAAAA==", |
| | | "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.001642|", |
| | | "WhenOpened": "2026-03-12T10:06:27.509Z" |
| | | }, |
| | | { |
| | | "$type": "Document", |
| | | "DocumentIndex": 13, |
| | | "DocumentIndex": 1, |
| | | "Title": "Program.cs", |
| | | "DocumentMoniker": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WMS\\WIDESEA_WMSServer\\WIDESEA_WMSServer\\Program.cs", |
| | | "RelativeDocumentMoniker": "WIDESEA_WMSServer\\Program.cs", |
| | | "ToolTip": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WMS\\WIDESEA_WMSServer\\WIDESEA_WMSServer\\Program.cs", |
| | | "RelativeToolTip": "WIDESEA_WMSServer\\Program.cs", |
| | | "ViewState": "AgIAABcAAAAAAAAAAAAswCYAAAAAAAAAAAAAAA==", |
| | | "ViewState": "AgIAACIAAAAAAAAAAAAiwDcAAAAYAAAAAAAAAA==", |
| | | "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|", |
| | | "WhenOpened": "2026-03-12T09:52:09.124Z" |
| | | }, |
| | | { |
| | | "$type": "Document", |
| | | "DocumentIndex": 7, |
| | | "Title": "StockStatusEmun.cs", |
| | | "DocumentMoniker": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WMS\\WIDESEA_WMSServer\\WIDESEA_Common\\StockEnum\\StockStatusEmun.cs", |
| | | "RelativeDocumentMoniker": "WIDESEA_Common\\StockEnum\\StockStatusEmun.cs", |
| | | "ToolTip": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WMS\\WIDESEA_WMSServer\\WIDESEA_Common\\StockEnum\\StockStatusEmun.cs", |
| | | "RelativeToolTip": "WIDESEA_Common\\StockEnum\\StockStatusEmun.cs", |
| | | "ViewState": "AgIAACMAAAAAAAAAAAAewDsAAAAIAAAAAAAAAA==", |
| | | "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|", |
| | | "WhenOpened": "2026-03-12T09:08:34.784Z" |
| | | }, |
| | | { |
| | | "$type": "Document", |
| | | "DocumentIndex": 11, |
| | | "Title": "TaskStatusEnum.cs", |
| | | "DocumentMoniker": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WMS\\WIDESEA_WMSServer\\WIDESEA_Common\\TaskEnum\\TaskStatusEnum.cs", |
| | | "RelativeDocumentMoniker": "WIDESEA_Common\\TaskEnum\\TaskStatusEnum.cs", |
| | | "ToolTip": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WMS\\WIDESEA_WMSServer\\WIDESEA_Common\\TaskEnum\\TaskStatusEnum.cs", |
| | | "RelativeToolTip": "WIDESEA_Common\\TaskEnum\\TaskStatusEnum.cs", |
| | | "ViewState": "AgIAAJsAAAAAAAAAAAAAwKkAAAASAAAAAAAAAA==", |
| | | "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|", |
| | | "WhenOpened": "2026-03-12T07:20:25.969Z" |
| | | }, |
| | | { |
| | | "$type": "Document", |
| | | "DocumentIndex": 8, |
| | | "Title": "LocationInfoService.cs", |
| | | "DocumentMoniker": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WMS\\WIDESEA_WMSServer\\WIDESEA_BasicService\\LocationInfoService.cs", |
| | | "RelativeDocumentMoniker": "WIDESEA_BasicService\\LocationInfoService.cs", |
| | | "ToolTip": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WMS\\WIDESEA_WMSServer\\WIDESEA_BasicService\\LocationInfoService.cs", |
| | | "RelativeToolTip": "WIDESEA_BasicService\\LocationInfoService.cs", |
| | | "ViewState": "AgIAAFcAAAAAAAAAAAAAwGgAAAARAAAAAAAAAA==", |
| | | "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|", |
| | | "WhenOpened": "2026-03-12T02:05:14.224Z", |
| | | "WhenOpened": "2026-03-25T08:48:13.949Z", |
| | | "EditorCaption": "" |
| | | }, |
| | | { |
| | | "$type": "Document", |
| | | "DocumentIndex": 14, |
| | | "Title": "LocationInfoController.cs", |
| | | "DocumentMoniker": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WMS\\WIDESEA_WMSServer\\WIDESEA_WMSServer\\Controllers\\Basic\\LocationInfoController.cs", |
| | | "RelativeDocumentMoniker": "WIDESEA_WMSServer\\Controllers\\Basic\\LocationInfoController.cs", |
| | | "ToolTip": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WMS\\WIDESEA_WMSServer\\WIDESEA_WMSServer\\Controllers\\Basic\\LocationInfoController.cs", |
| | | "RelativeToolTip": "WIDESEA_WMSServer\\Controllers\\Basic\\LocationInfoController.cs", |
| | | "ViewState": "AgIAAEkAAAAAAAAAAAAIwF8AAAAsAAAAAAAAAA==", |
| | | "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|", |
| | | "WhenOpened": "2026-03-12T01:53:01.837Z" |
| | | "DocumentIndex": 0, |
| | | "Title": "appsettings.json", |
| | | "DocumentMoniker": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WMS\\WIDESEA_WMSServer\\WIDESEA_WMSServer\\appsettings.json", |
| | | "RelativeDocumentMoniker": "WIDESEA_WMSServer\\appsettings.json", |
| | | "ToolTip": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WMS\\WIDESEA_WMSServer\\WIDESEA_WMSServer\\appsettings.json", |
| | | "RelativeToolTip": "WIDESEA_WMSServer\\appsettings.json", |
| | | "ViewState": "AgIAAAAAAAAAAAAAAAAAAAcAAAAoAAAAAAAAAA==", |
| | | "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.001642|", |
| | | "WhenOpened": "2026-03-25T08:40:34.998Z", |
| | | "EditorCaption": "" |
| | | }, |
| | | { |
| | | "$type": "Document", |
| | | "DocumentIndex": 2, |
| | | "Title": "StockInfoService.cs", |
| | | "DocumentMoniker": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WMS\\WIDESEA_WMSServer\\WIDESEA_StockService\\StockInfoService.cs", |
| | | "RelativeDocumentMoniker": "WIDESEA_StockService\\StockInfoService.cs", |
| | | "ToolTip": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WMS\\WIDESEA_WMSServer\\WIDESEA_StockService\\StockInfoService.cs", |
| | | "RelativeToolTip": "WIDESEA_StockService\\StockInfoService.cs", |
| | | "ViewState": "AgIAADQAAAAAAAAAAAAIwDkAAAAuAAAAAAAAAA==", |
| | | "Title": "ServiceBase.cs", |
| | | "DocumentMoniker": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WMS\\WIDESEA_WMSServer\\WIDESEA_Core\\BaseServices\\ServiceBase.cs", |
| | | "RelativeDocumentMoniker": "WIDESEA_Core\\BaseServices\\ServiceBase.cs", |
| | | "ToolTip": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WMS\\WIDESEA_WMSServer\\WIDESEA_Core\\BaseServices\\ServiceBase.cs", |
| | | "RelativeToolTip": "WIDESEA_Core\\BaseServices\\ServiceBase.cs", |
| | | "ViewState": "AgIAACsCAAAAAAAAAAASwEACAAAIAAAAAAAAAA==", |
| | | "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|", |
| | | "WhenOpened": "2026-03-11T09:16:37.34Z" |
| | | }, |
| | | { |
| | | "$type": "Document", |
| | | "DocumentIndex": 1, |
| | | "Title": "StockSerivce.cs", |
| | | "DocumentMoniker": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WMS\\WIDESEA_WMSServer\\WIDESEA_StockService\\StockSerivce.cs", |
| | | "RelativeDocumentMoniker": "WIDESEA_StockService\\StockSerivce.cs", |
| | | "ToolTip": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WMS\\WIDESEA_WMSServer\\WIDESEA_StockService\\StockSerivce.cs", |
| | | "RelativeToolTip": "WIDESEA_StockService\\StockSerivce.cs", |
| | | "ViewState": "AgIAAAAAAAAAAAAAAAAAABkAAAAWAAAAAAAAAA==", |
| | | "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|", |
| | | "WhenOpened": "2026-03-17T02:09:23.282Z", |
| | | "EditorCaption": "" |
| | | }, |
| | | { |
| | | "$type": "Document", |
| | | "DocumentIndex": 3, |
| | | "Title": "TaskService.cs", |
| | | "DocumentMoniker": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WMS\\WIDESEA_WMSServer\\WIDESEA_TaskInfoService\\TaskService.cs", |
| | | "RelativeDocumentMoniker": "WIDESEA_TaskInfoService\\TaskService.cs", |
| | | "ToolTip": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WMS\\WIDESEA_WMSServer\\WIDESEA_TaskInfoService\\TaskService.cs", |
| | | "RelativeToolTip": "WIDESEA_TaskInfoService\\TaskService.cs", |
| | | "ViewState": "AgIAACkAAAAAAAAAAAAywBAAAAAcAAAAAAAAAA==", |
| | | "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|", |
| | | "WhenOpened": "2026-02-06T06:34:59.734Z", |
| | | "WhenOpened": "2026-03-25T06:03:58.013Z", |
| | | "EditorCaption": "" |
| | | } |
| | | ] |
| | |
| | | "WorkspaceRootPath": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WMS\\WIDESEA_WMSServer\\", |
| | | "Documents": [ |
| | | { |
| | | "AbsoluteMoniker": "D:0:0:{D81A65B5-47D1-40C1-8FDE-7D24FF003F51}|WIDESEA_WMSServer\\WIDESEA_WMSServer.csproj|d:\\git\\shanmeixinnengyuan\\code\\wms\\widesea_wmsserver\\widesea_wmsserver\\backgroundservices\\autooutboundtaskbackgroundservice.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}", |
| | | "RelativeMoniker": "D:0:0:{D81A65B5-47D1-40C1-8FDE-7D24FF003F51}|WIDESEA_WMSServer\\WIDESEA_WMSServer.csproj|solutionrelative:widesea_wmsserver\\backgroundservices\\autooutboundtaskbackgroundservice.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}" |
| | | }, |
| | | { |
| | | "AbsoluteMoniker": "D:0:0:{7DC26D42-D8EE-46F0-BA66-A13457086885}|WIDESEA_StockService\\WIDESEA_StockService.csproj|d:\\git\\shanmeixinnengyuan\\code\\wms\\widesea_wmsserver\\widesea_stockservice\\stockserivce.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}", |
| | | "RelativeMoniker": "D:0:0:{7DC26D42-D8EE-46F0-BA66-A13457086885}|WIDESEA_StockService\\WIDESEA_StockService.csproj|solutionrelative:widesea_stockservice\\stockserivce.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}" |
| | | }, |
| | | { |
| | | "AbsoluteMoniker": "D:0:0:{7DC26D42-D8EE-46F0-BA66-A13457086885}|WIDESEA_StockService\\WIDESEA_StockService.csproj|d:\\git\\shanmeixinnengyuan\\code\\wms\\widesea_wmsserver\\widesea_stockservice\\stockinfoservice.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}", |
| | | "RelativeMoniker": "D:0:0:{7DC26D42-D8EE-46F0-BA66-A13457086885}|WIDESEA_StockService\\WIDESEA_StockService.csproj|solutionrelative:widesea_stockservice\\stockinfoservice.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}" |
| | | }, |
| | | { |
| | | "AbsoluteMoniker": "D:0:0:{7D7534D4-51D9-46DC-A6B7-6430042F4E12}|WIDESEA_TaskInfoService\\WIDESEA_TaskInfoService.csproj|d:\\git\\shanmeixinnengyuan\\code\\wms\\widesea_wmsserver\\widesea_taskinfoservice\\taskservice.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}", |
| | | "RelativeMoniker": "D:0:0:{7D7534D4-51D9-46DC-A6B7-6430042F4E12}|WIDESEA_TaskInfoService\\WIDESEA_TaskInfoService.csproj|solutionrelative:widesea_taskinfoservice\\taskservice.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}" |
| | | }, |
| | | { |
| | | "AbsoluteMoniker": "D:0:0:{929DF936-042C-4EEC-8722-A831FC2F0AEA}|WIDESEA_DTO\\WIDESEA_DTO.csproj|d:\\git\\shanmeixinnengyuan\\code\\wms\\widesea_wmsserver\\widesea_dto\\task\\wmstaskdto.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}", |
| | | "RelativeMoniker": "D:0:0:{929DF936-042C-4EEC-8722-A831FC2F0AEA}|WIDESEA_DTO\\WIDESEA_DTO.csproj|solutionrelative:widesea_dto\\task\\wmstaskdto.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}" |
| | | }, |
| | | { |
| | | "AbsoluteMoniker": "D:0:0:{D81A65B5-47D1-40C1-8FDE-7D24FF003F51}|WIDESEA_WMSServer\\WIDESEA_WMSServer.csproj|d:\\git\\shanmeixinnengyuan\\code\\wms\\widesea_wmsserver\\widesea_wmsserver\\controllers\\taskinfo\\taskcontroller.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}", |
| | | "RelativeMoniker": "D:0:0:{D81A65B5-47D1-40C1-8FDE-7D24FF003F51}|WIDESEA_WMSServer\\WIDESEA_WMSServer.csproj|solutionrelative:widesea_wmsserver\\controllers\\taskinfo\\taskcontroller.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}" |
| | | }, |
| | | { |
| | | "AbsoluteMoniker": "D:0:0:{AF8F3D65-1D75-4B8F-AFD9-4150E591C44D}|WIDESEA_Common\\WIDESEA_Common.csproj|d:\\git\\shanmeixinnengyuan\\code\\wms\\widesea_wmsserver\\widesea_common\\taskenum\\tasktypeenum.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}", |
| | | "RelativeMoniker": "D:0:0:{AF8F3D65-1D75-4B8F-AFD9-4150E591C44D}|WIDESEA_Common\\WIDESEA_Common.csproj|solutionrelative:widesea_common\\taskenum\\tasktypeenum.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}" |
| | | }, |
| | | { |
| | | "AbsoluteMoniker": "D:0:0:{AF8F3D65-1D75-4B8F-AFD9-4150E591C44D}|WIDESEA_Common\\WIDESEA_Common.csproj|d:\\git\\shanmeixinnengyuan\\code\\wms\\widesea_wmsserver\\widesea_common\\stockenum\\stockstatusemun.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}", |
| | | "RelativeMoniker": "D:0:0:{AF8F3D65-1D75-4B8F-AFD9-4150E591C44D}|WIDESEA_Common\\WIDESEA_Common.csproj|solutionrelative:widesea_common\\stockenum\\stockstatusemun.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}" |
| | | }, |
| | | { |
| | | "AbsoluteMoniker": "D:0:0:{D11C804C-2FF4-4C18-A3EE-2F0574427BB3}|WIDESEA_BasicService\\WIDESEA_BasicService.csproj|d:\\git\\shanmeixinnengyuan\\code\\wms\\widesea_wmsserver\\widesea_basicservice\\locationinfoservice.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}", |
| | | "RelativeMoniker": "D:0:0:{D11C804C-2FF4-4C18-A3EE-2F0574427BB3}|WIDESEA_BasicService\\WIDESEA_BasicService.csproj|solutionrelative:widesea_basicservice\\locationinfoservice.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}" |
| | | }, |
| | | { |
| | | "AbsoluteMoniker": "D:0:0:{929DF936-042C-4EEC-8722-A831FC2F0AEA}|WIDESEA_DTO\\WIDESEA_DTO.csproj|d:\\git\\shanmeixinnengyuan\\code\\wms\\widesea_wmsserver\\widesea_dto\\stock\\stockdto.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}", |
| | | "RelativeMoniker": "D:0:0:{929DF936-042C-4EEC-8722-A831FC2F0AEA}|WIDESEA_DTO\\WIDESEA_DTO.csproj|solutionrelative:widesea_dto\\stock\\stockdto.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}" |
| | | }, |
| | | { |
| | | "AbsoluteMoniker": "D:0:0:{CE0DB91F-5A68-448E-A419-4C26B5039F51}|WIDESEA_ITaskInfoService\\WIDESEA_ITaskInfoService.csproj|d:\\git\\shanmeixinnengyuan\\code\\wms\\widesea_wmsserver\\widesea_itaskinfoservice\\itaskservice.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}", |
| | | "RelativeMoniker": "D:0:0:{CE0DB91F-5A68-448E-A419-4C26B5039F51}|WIDESEA_ITaskInfoService\\WIDESEA_ITaskInfoService.csproj|solutionrelative:widesea_itaskinfoservice\\itaskservice.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}" |
| | | }, |
| | | { |
| | | "AbsoluteMoniker": "D:0:0:{AF8F3D65-1D75-4B8F-AFD9-4150E591C44D}|WIDESEA_Common\\WIDESEA_Common.csproj|d:\\git\\shanmeixinnengyuan\\code\\wms\\widesea_wmsserver\\widesea_common\\taskenum\\taskstatusenum.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}", |
| | | "RelativeMoniker": "D:0:0:{AF8F3D65-1D75-4B8F-AFD9-4150E591C44D}|WIDESEA_Common\\WIDESEA_Common.csproj|solutionrelative:widesea_common\\taskenum\\taskstatusenum.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}" |
| | | "AbsoluteMoniker": "D:0:0:{111BD7AA-9749-4506-9772-79F9EF14754C}|WIDESEA_Core\\WIDESEA_Core.csproj|d:\\git\\shanmeixinnengyuan\\code\\wms\\widesea_wmsserver\\widesea_core\\baseservices\\servicebase.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}", |
| | | "RelativeMoniker": "D:0:0:{111BD7AA-9749-4506-9772-79F9EF14754C}|WIDESEA_Core\\WIDESEA_Core.csproj|solutionrelative:widesea_core\\baseservices\\servicebase.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}" |
| | | }, |
| | | { |
| | | "AbsoluteMoniker": "D:0:0:{D81A65B5-47D1-40C1-8FDE-7D24FF003F51}|WIDESEA_WMSServer\\WIDESEA_WMSServer.csproj|d:\\git\\shanmeixinnengyuan\\code\\wms\\widesea_wmsserver\\widesea_wmsserver\\appsettings.json||{90A6B3A7-C1A3-4009-A288-E2FF89E96FA0}", |
| | | "RelativeMoniker": "D:0:0:{D81A65B5-47D1-40C1-8FDE-7D24FF003F51}|WIDESEA_WMSServer\\WIDESEA_WMSServer.csproj|solutionrelative:widesea_wmsserver\\appsettings.json||{90A6B3A7-C1A3-4009-A288-E2FF89E96FA0}" |
| | | }, |
| | | { |
| | | "AbsoluteMoniker": "D:0:0:{D81A65B5-47D1-40C1-8FDE-7D24FF003F51}|WIDESEA_WMSServer\\WIDESEA_WMSServer.csproj|d:\\git\\shanmeixinnengyuan\\code\\wms\\widesea_wmsserver\\widesea_wmsserver\\program.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}", |
| | | "RelativeMoniker": "D:0:0:{D81A65B5-47D1-40C1-8FDE-7D24FF003F51}|WIDESEA_WMSServer\\WIDESEA_WMSServer.csproj|solutionrelative:widesea_wmsserver\\program.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}" |
| | | }, |
| | | { |
| | | "AbsoluteMoniker": "D:0:0:{D81A65B5-47D1-40C1-8FDE-7D24FF003F51}|WIDESEA_WMSServer\\WIDESEA_WMSServer.csproj|d:\\git\\shanmeixinnengyuan\\code\\wms\\widesea_wmsserver\\widesea_wmsserver\\controllers\\basic\\locationinfocontroller.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}", |
| | | "RelativeMoniker": "D:0:0:{D81A65B5-47D1-40C1-8FDE-7D24FF003F51}|WIDESEA_WMSServer\\WIDESEA_WMSServer.csproj|solutionrelative:widesea_wmsserver\\controllers\\basic\\locationinfocontroller.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}" |
| | | } |
| | | ], |
| | | "DocumentGroupContainers": [ |
| | |
| | | "DocumentGroups": [ |
| | | { |
| | | "DockedWidth": 200, |
| | | "SelectedChildIndex": 8, |
| | | "SelectedChildIndex": 3, |
| | | "Children": [ |
| | | { |
| | | "$type": "Bookmark", |
| | |
| | | }, |
| | | { |
| | | "$type": "Document", |
| | | "DocumentIndex": 4, |
| | | "Title": "WMSTaskDTO.cs", |
| | | "DocumentMoniker": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WMS\\WIDESEA_WMSServer\\WIDESEA_DTO\\Task\\WMSTaskDTO.cs", |
| | | "RelativeDocumentMoniker": "WIDESEA_DTO\\Task\\WMSTaskDTO.cs", |
| | | "ToolTip": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WMS\\WIDESEA_WMSServer\\WIDESEA_DTO\\Task\\WMSTaskDTO.cs", |
| | | "RelativeToolTip": "WIDESEA_DTO\\Task\\WMSTaskDTO.cs", |
| | | "ViewState": "AgIAABgAAAAAAAAAAAAIwCkAAAAdAAAAAAAAAA==", |
| | | "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|", |
| | | "WhenOpened": "2026-03-17T07:42:09.48Z" |
| | | }, |
| | | { |
| | | "$type": "Document", |
| | | "DocumentIndex": 9, |
| | | "Title": "StockDTO.cs", |
| | | "DocumentMoniker": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WMS\\WIDESEA_WMSServer\\WIDESEA_DTO\\Stock\\StockDTO.cs", |
| | | "RelativeDocumentMoniker": "WIDESEA_DTO\\Stock\\StockDTO.cs", |
| | | "ToolTip": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WMS\\WIDESEA_WMSServer\\WIDESEA_DTO\\Stock\\StockDTO.cs", |
| | | "RelativeToolTip": "WIDESEA_DTO\\Stock\\StockDTO.cs", |
| | | "ViewState": "AgIAAA8AAAAAAAAAAAAIwAoAAAA+AAAAAAAAAA==", |
| | | "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|", |
| | | "WhenOpened": "2026-03-17T03:01:04.659Z" |
| | | }, |
| | | { |
| | | "$type": "Document", |
| | | "DocumentIndex": 10, |
| | | "Title": "ITaskService.cs", |
| | | "DocumentMoniker": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WMS\\WIDESEA_WMSServer\\WIDESEA_ITaskInfoService\\ITaskService.cs", |
| | | "RelativeDocumentMoniker": "WIDESEA_ITaskInfoService\\ITaskService.cs", |
| | | "ToolTip": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WMS\\WIDESEA_WMSServer\\WIDESEA_ITaskInfoService\\ITaskService.cs", |
| | | "RelativeToolTip": "WIDESEA_ITaskInfoService\\ITaskService.cs", |
| | | "ViewState": "AgIAAIIAAAAAAAAAAAAMwIkAAAAVAAAAAAAAAA==", |
| | | "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|", |
| | | "WhenOpened": "2026-03-17T03:12:58.977Z" |
| | | }, |
| | | { |
| | | "$type": "Document", |
| | | "DocumentIndex": 6, |
| | | "Title": "TaskTypeEnum.cs", |
| | | "DocumentMoniker": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WMS\\WIDESEA_WMSServer\\WIDESEA_Common\\TaskEnum\\TaskTypeEnum.cs", |
| | | "RelativeDocumentMoniker": "WIDESEA_Common\\TaskEnum\\TaskTypeEnum.cs", |
| | | "ToolTip": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WMS\\WIDESEA_WMSServer\\WIDESEA_Common\\TaskEnum\\TaskTypeEnum.cs", |
| | | "RelativeToolTip": "WIDESEA_Common\\TaskEnum\\TaskTypeEnum.cs", |
| | | "ViewState": "AgIAAIsAAAAAAAAAAAAewKAAAAAIAAAAAAAAAA==", |
| | | "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|", |
| | | "WhenOpened": "2026-03-17T02:28:48.033Z" |
| | | }, |
| | | { |
| | | "$type": "Document", |
| | | "DocumentIndex": 5, |
| | | "Title": "TaskController.cs", |
| | | "DocumentMoniker": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WMS\\WIDESEA_WMSServer\\WIDESEA_WMSServer\\Controllers\\TaskInfo\\TaskController.cs", |
| | | "RelativeDocumentMoniker": "WIDESEA_WMSServer\\Controllers\\TaskInfo\\TaskController.cs", |
| | | "ToolTip": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WMS\\WIDESEA_WMSServer\\WIDESEA_WMSServer\\Controllers\\TaskInfo\\TaskController.cs", |
| | | "RelativeToolTip": "WIDESEA_WMSServer\\Controllers\\TaskInfo\\TaskController.cs", |
| | | "ViewState": "AgIAAIoAAAAAAAAAAAAhwJsAAAAIAAAAAAAAAA==", |
| | | "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|", |
| | | "WhenOpened": "2026-03-13T02:00:31.089Z" |
| | | }, |
| | | { |
| | | "$type": "Document", |
| | | "DocumentIndex": 0, |
| | | "Title": "AutoOutboundTaskBackgroundService.cs", |
| | | "DocumentMoniker": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WMS\\WIDESEA_WMSServer\\WIDESEA_WMSServer\\BackgroundServices\\AutoOutboundTaskBackgroundService.cs", |
| | | "RelativeDocumentMoniker": "WIDESEA_WMSServer\\BackgroundServices\\AutoOutboundTaskBackgroundService.cs", |
| | | "ToolTip": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WMS\\WIDESEA_WMSServer\\WIDESEA_WMSServer\\BackgroundServices\\AutoOutboundTaskBackgroundService.cs", |
| | | "RelativeToolTip": "WIDESEA_WMSServer\\BackgroundServices\\AutoOutboundTaskBackgroundService.cs", |
| | | "ViewState": "AgIAABQAAAAAAAAAAADwvykAAABdAAAAAAAAAA==", |
| | | "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|", |
| | | "WhenOpened": "2026-03-12T10:18:13.91Z", |
| | | "EditorCaption": "" |
| | | }, |
| | | { |
| | | "$type": "Document", |
| | | "DocumentIndex": 12, |
| | | "Title": "appsettings.json", |
| | | "DocumentMoniker": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WMS\\WIDESEA_WMSServer\\WIDESEA_WMSServer\\appsettings.json", |
| | | "RelativeDocumentMoniker": "WIDESEA_WMSServer\\appsettings.json", |
| | | "ToolTip": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WMS\\WIDESEA_WMSServer\\WIDESEA_WMSServer\\appsettings.json", |
| | | "RelativeToolTip": "WIDESEA_WMSServer\\appsettings.json", |
| | | "ViewState": "AgIAAAAAAAAAAAAAAAAAABgAAAA9AAAAAAAAAA==", |
| | | "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.001642|", |
| | | "WhenOpened": "2026-03-12T10:06:27.509Z" |
| | | }, |
| | | { |
| | | "$type": "Document", |
| | | "DocumentIndex": 13, |
| | | "Title": "Program.cs", |
| | | "DocumentMoniker": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WMS\\WIDESEA_WMSServer\\WIDESEA_WMSServer\\Program.cs", |
| | | "RelativeDocumentMoniker": "WIDESEA_WMSServer\\Program.cs", |
| | | "ToolTip": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WMS\\WIDESEA_WMSServer\\WIDESEA_WMSServer\\Program.cs", |
| | | "RelativeToolTip": "WIDESEA_WMSServer\\Program.cs", |
| | | "ViewState": "AgIAABcAAAAAAAAAAAAswCYAAAAAAAAAAAAAAA==", |
| | | "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|", |
| | | "WhenOpened": "2026-03-12T09:52:09.124Z" |
| | | }, |
| | | { |
| | | "$type": "Document", |
| | | "DocumentIndex": 7, |
| | | "Title": "StockStatusEmun.cs", |
| | | "DocumentMoniker": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WMS\\WIDESEA_WMSServer\\WIDESEA_Common\\StockEnum\\StockStatusEmun.cs", |
| | | "RelativeDocumentMoniker": "WIDESEA_Common\\StockEnum\\StockStatusEmun.cs", |
| | | "ToolTip": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WMS\\WIDESEA_WMSServer\\WIDESEA_Common\\StockEnum\\StockStatusEmun.cs", |
| | | "RelativeToolTip": "WIDESEA_Common\\StockEnum\\StockStatusEmun.cs", |
| | | "ViewState": "AgIAACMAAAAAAAAAAAAewDsAAAAIAAAAAAAAAA==", |
| | | "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|", |
| | | "WhenOpened": "2026-03-12T09:08:34.784Z" |
| | | }, |
| | | { |
| | | "$type": "Document", |
| | | "DocumentIndex": 11, |
| | | "Title": "TaskStatusEnum.cs", |
| | | "DocumentMoniker": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WMS\\WIDESEA_WMSServer\\WIDESEA_Common\\TaskEnum\\TaskStatusEnum.cs", |
| | | "RelativeDocumentMoniker": "WIDESEA_Common\\TaskEnum\\TaskStatusEnum.cs", |
| | | "ToolTip": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WMS\\WIDESEA_WMSServer\\WIDESEA_Common\\TaskEnum\\TaskStatusEnum.cs", |
| | | "RelativeToolTip": "WIDESEA_Common\\TaskEnum\\TaskStatusEnum.cs", |
| | | "ViewState": "AgIAAJsAAAAAAAAAAAAAwKkAAAASAAAAAAAAAA==", |
| | | "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|", |
| | | "WhenOpened": "2026-03-12T07:20:25.969Z" |
| | | }, |
| | | { |
| | | "$type": "Document", |
| | | "DocumentIndex": 8, |
| | | "Title": "LocationInfoService.cs", |
| | | "DocumentMoniker": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WMS\\WIDESEA_WMSServer\\WIDESEA_BasicService\\LocationInfoService.cs", |
| | | "RelativeDocumentMoniker": "WIDESEA_BasicService\\LocationInfoService.cs", |
| | | "ToolTip": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WMS\\WIDESEA_WMSServer\\WIDESEA_BasicService\\LocationInfoService.cs", |
| | | "RelativeToolTip": "WIDESEA_BasicService\\LocationInfoService.cs", |
| | | "ViewState": "AgIAAFcAAAAAAAAAAAAAwGgAAAARAAAAAAAAAA==", |
| | | "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|", |
| | | "WhenOpened": "2026-03-12T02:05:14.224Z" |
| | | }, |
| | | { |
| | | "$type": "Document", |
| | | "DocumentIndex": 14, |
| | | "Title": "LocationInfoController.cs", |
| | | "DocumentMoniker": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WMS\\WIDESEA_WMSServer\\WIDESEA_WMSServer\\Controllers\\Basic\\LocationInfoController.cs", |
| | | "RelativeDocumentMoniker": "WIDESEA_WMSServer\\Controllers\\Basic\\LocationInfoController.cs", |
| | | "ToolTip": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WMS\\WIDESEA_WMSServer\\WIDESEA_WMSServer\\Controllers\\Basic\\LocationInfoController.cs", |
| | | "RelativeToolTip": "WIDESEA_WMSServer\\Controllers\\Basic\\LocationInfoController.cs", |
| | | "ViewState": "AgIAAEkAAAAAAAAAAAAIwF8AAAAsAAAAAAAAAA==", |
| | | "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|", |
| | | "WhenOpened": "2026-03-12T01:53:01.837Z" |
| | | }, |
| | | { |
| | | "$type": "Document", |
| | | "DocumentIndex": 2, |
| | | "Title": "StockInfoService.cs", |
| | | "DocumentMoniker": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WMS\\WIDESEA_WMSServer\\WIDESEA_StockService\\StockInfoService.cs", |
| | | "RelativeDocumentMoniker": "WIDESEA_StockService\\StockInfoService.cs", |
| | | "ToolTip": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WMS\\WIDESEA_WMSServer\\WIDESEA_StockService\\StockInfoService.cs", |
| | | "RelativeToolTip": "WIDESEA_StockService\\StockInfoService.cs", |
| | | "ViewState": "AgIAADQAAAAAAAAAAAAIwDkAAAAuAAAAAAAAAA==", |
| | | "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|", |
| | | "WhenOpened": "2026-03-11T09:16:37.34Z" |
| | | }, |
| | | { |
| | | "$type": "Document", |
| | | "DocumentIndex": 1, |
| | | "Title": "StockSerivce.cs", |
| | | "DocumentMoniker": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WMS\\WIDESEA_WMSServer\\WIDESEA_StockService\\StockSerivce.cs", |
| | | "RelativeDocumentMoniker": "WIDESEA_StockService\\StockSerivce.cs", |
| | | "ToolTip": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WMS\\WIDESEA_WMSServer\\WIDESEA_StockService\\StockSerivce.cs", |
| | | "RelativeToolTip": "WIDESEA_StockService\\StockSerivce.cs", |
| | | "ViewState": "AgIAAAAAAAAAAAAAAAAAABkAAAAWAAAAAAAAAA==", |
| | | "ViewState": "AgIAAHcAAAAAAAAAAAAIwIoAAAASAAAAAAAAAA==", |
| | | "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|", |
| | | "WhenOpened": "2026-03-17T02:09:23.282Z" |
| | | "WhenOpened": "2026-03-26T01:10:20.079Z", |
| | | "EditorCaption": "" |
| | | }, |
| | | { |
| | | "$type": "Document", |
| | | "DocumentIndex": 3, |
| | | "Title": "TaskService.cs", |
| | | "DocumentMoniker": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WMS\\WIDESEA_WMSServer\\WIDESEA_TaskInfoService\\TaskService.cs", |
| | | "RelativeDocumentMoniker": "WIDESEA_TaskInfoService\\TaskService.cs", |
| | | "ToolTip": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WMS\\WIDESEA_WMSServer\\WIDESEA_TaskInfoService\\TaskService.cs", |
| | | "RelativeToolTip": "WIDESEA_TaskInfoService\\TaskService.cs", |
| | | "ViewState": "AgIAACkAAAAAAAAAAAAywBAAAAAcAAAAAAAAAA==", |
| | | "DocumentIndex": 2, |
| | | "Title": "appsettings.json", |
| | | "DocumentMoniker": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WMS\\WIDESEA_WMSServer\\WIDESEA_WMSServer\\appsettings.json", |
| | | "RelativeDocumentMoniker": "WIDESEA_WMSServer\\appsettings.json", |
| | | "ToolTip": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WMS\\WIDESEA_WMSServer\\WIDESEA_WMSServer\\appsettings.json", |
| | | "RelativeToolTip": "WIDESEA_WMSServer\\appsettings.json", |
| | | "ViewState": "AgIAAAAAAAAAAAAAAAAAABMAAAAfAAAAAAAAAA==", |
| | | "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.001642|", |
| | | "WhenOpened": "2026-03-25T08:40:34.998Z", |
| | | "EditorCaption": "" |
| | | }, |
| | | { |
| | | "$type": "Document", |
| | | "DocumentIndex": 1, |
| | | "Title": "ServiceBase.cs", |
| | | "DocumentMoniker": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WMS\\WIDESEA_WMSServer\\WIDESEA_Core\\BaseServices\\ServiceBase.cs", |
| | | "RelativeDocumentMoniker": "WIDESEA_Core\\BaseServices\\ServiceBase.cs", |
| | | "ToolTip": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WMS\\WIDESEA_WMSServer\\WIDESEA_Core\\BaseServices\\ServiceBase.cs", |
| | | "RelativeToolTip": "WIDESEA_Core\\BaseServices\\ServiceBase.cs", |
| | | "ViewState": "AgIAABoAAAAAAAAAAAAuwD8AAAARAAAAAAAAAA==", |
| | | "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|", |
| | | "WhenOpened": "2026-02-06T06:34:59.734Z" |
| | | "WhenOpened": "2026-03-25T06:03:58.013Z", |
| | | "EditorCaption": "" |
| | | } |
| | | ] |
| | | } |
| | |
| | | |
| | | public ISqlSugarClient Db => BaseDal.Db; |
| | | |
| | | protected async Task<WebResponseContent> ExecuteWithinTransactionAsync(Func<Task<WebResponseContent>> operation) |
| | | { |
| | | var db = Db as SqlSugarClient; |
| | | if (db == null) |
| | | { |
| | | return WebResponseContent.Instance.Error("Database context does not support transactions"); |
| | | } |
| | | |
| | | var ownsTransaction = db.Ado.Transaction == null; |
| | | try |
| | | { |
| | | if (ownsTransaction) |
| | | { |
| | | db.BeginTran(); |
| | | } |
| | | |
| | | var result = await operation(); |
| | | if (result?.Status == true) |
| | | { |
| | | if (ownsTransaction) |
| | | { |
| | | db.CommitTran(); |
| | | } |
| | | |
| | | return result; |
| | | } |
| | | |
| | | if (ownsTransaction) |
| | | { |
| | | db.RollbackTran(); |
| | | } |
| | | |
| | | return result ?? WebResponseContent.Instance.Error("Transaction failed"); |
| | | } |
| | | catch |
| | | { |
| | | if (ownsTransaction) |
| | | { |
| | | db.RollbackTran(); |
| | | } |
| | | |
| | | throw; |
| | | } |
| | | } |
| | | |
| | | private PropertyInfo[] _propertyInfo { get; set; } = null; |
| | | public PropertyInfo[] TProperties |
| | | { |
| | |
| | | using WIDESEA_Common.StockEnum; |
| | | using SqlSugar; |
| | | using WIDESEA_Common.StockEnum; |
| | | using WIDESEA_Core; |
| | | using WIDESEA_DTO.Stock; |
| | | using WIDESEA_IStockService; |
| | |
| | | } |
| | | |
| | | /// <summary> |
| | | /// å¨äºå¡ä¸æ§è¡æä½ |
| | | /// </summary> |
| | | private async Task<WebResponseContent> ExecuteWithinTransactionAsync(Func<Task<WebResponseContent>> operation) |
| | | { |
| | | var db = StockInfoService.Repository.Db as SqlSugarClient; |
| | | if (db == null) |
| | | { |
| | | return WebResponseContent.Instance.Error("Database context does not support transactions"); |
| | | } |
| | | |
| | | var ownsTransaction = db.Ado.Transaction == null; |
| | | try |
| | | { |
| | | if (ownsTransaction) |
| | | { |
| | | db.BeginTran(); |
| | | } |
| | | |
| | | var result = await operation(); |
| | | if (result?.Status == true) |
| | | { |
| | | if (ownsTransaction) |
| | | { |
| | | db.CommitTran(); |
| | | } |
| | | return result; |
| | | } |
| | | |
| | | if (ownsTransaction) |
| | | { |
| | | db.RollbackTran(); |
| | | } |
| | | return result ?? WebResponseContent.Instance.Error("Transaction failed"); |
| | | } |
| | | catch |
| | | { |
| | | if (ownsTransaction) |
| | | { |
| | | db.RollbackTran(); |
| | | } |
| | | throw; |
| | | } |
| | | } |
| | | |
| | | /// <summary> |
| | | /// ç»ç |
| | | /// </summary> |
| | | public async Task<WebResponseContent> GroupPalletAsync(StockDTO stock) |
| | |
| | | Status = StockStatusEmun.ç»çæå.GetHashCode(), |
| | | }).ToList(); |
| | | |
| | | var existingStock = StockInfoService.Repository.QueryFirst(s => s.PalletCode == stock.TargetPalletNo); |
| | | var result = false; |
| | | if (existingStock != null) |
| | | return await ExecuteWithinTransactionAsync(async () => |
| | | { |
| | | details.ForEach(d => d.StockId = existingStock.Id); |
| | | result = await StockInfoDetailService.Repository.AddDataAsync(details) > 0; |
| | | if (result) return content.OK("ç»çæå"); |
| | | return content.Error("ç»ç失败"); |
| | | } |
| | | var existingStock = StockInfoService.Repository.QueryFirst(s => s.PalletCode == stock.TargetPalletNo); |
| | | var result = false; |
| | | if (existingStock != null) |
| | | { |
| | | details.ForEach(d => d.StockId = existingStock.Id); |
| | | result = await StockInfoDetailService.Repository.AddDataAsync(details) > 0; |
| | | return result ? content.OK("ç»çæå") : content.Error("ç»ç失败"); |
| | | } |
| | | |
| | | var entity = new Dt_StockInfo |
| | | { |
| | | PalletCode = stock.TargetPalletNo, |
| | | WarehouseId = 1, |
| | | StockStatus = 1, |
| | | Creater = "system", |
| | | Details = details |
| | | }; |
| | | var entity = new Dt_StockInfo |
| | | { |
| | | PalletCode = stock.TargetPalletNo, |
| | | //WarehouseId = stock.WarehouseId > 0 ? stock.WarehouseId : 1, |
| | | WarehouseId = 1, |
| | | StockStatus = StockStatusEmun.ç»çæå.GetHashCode(), |
| | | Creater = "system", |
| | | Details = details |
| | | }; |
| | | |
| | | result = StockInfoService.Repository.AddData(entity, x => x.Details); |
| | | if (result) return content.OK("ç»çæå"); |
| | | return content.Error("ç»ç失败"); |
| | | result = StockInfoService.Repository.AddData(entity, x => x.Details); |
| | | return result ? content.OK("ç»çæå") : content.Error("ç»ç失败"); |
| | | }); |
| | | } |
| | | |
| | | /// <summary> |
| | |
| | | /// </summary> |
| | | public async Task<WebResponseContent> ChangePalletAsync(StockDTO stock) |
| | | { |
| | | |
| | | WebResponseContent content = new WebResponseContent(); |
| | | if (stock == null || |
| | | string.IsNullOrWhiteSpace(stock.TargetPalletNo) || |
| | |
| | | return content.Error("æºæçå·ä¸ç®æ æçå·ç¸å"); |
| | | } |
| | | |
| | | var sourceStock = await StockInfoService.Repository.QueryDataNavFirstAsync(s => s.PalletCode == stock.SourcePalletNo); |
| | | if (sourceStock == null) return content.Error("æºæçä¸åå¨"); |
| | | |
| | | var targetStock = StockInfoService.Repository.QueryFirst(s => s.PalletCode == stock.TargetPalletNo); |
| | | if (targetStock == null) |
| | | return await ExecuteWithinTransactionAsync(async () => |
| | | { |
| | | var newStock = new Dt_StockInfo |
| | | var sourceStock = await StockInfoService.Repository.QueryDataNavFirstAsync(s => s.PalletCode == stock.SourcePalletNo); |
| | | if (sourceStock == null) return content.Error("æºæçä¸åå¨"); |
| | | |
| | | var targetStock = StockInfoService.Repository.QueryFirst(s => s.PalletCode == stock.TargetPalletNo); |
| | | if (targetStock == null) |
| | | { |
| | | PalletCode = stock.TargetPalletNo, |
| | | WarehouseId = sourceStock.WarehouseId, |
| | | StockStatus = StockStatusEmun.ç»çæå.GetHashCode(), |
| | | Creater = "system", |
| | | }; |
| | | var newStock = new Dt_StockInfo |
| | | { |
| | | PalletCode = stock.TargetPalletNo, |
| | | WarehouseId = sourceStock.WarehouseId, |
| | | StockStatus = StockStatusEmun.ç»çæå.GetHashCode(), |
| | | Creater = "system", |
| | | }; |
| | | |
| | | var newId = StockInfoService.Repository.AddData(newStock); |
| | | if (newId <= 0) return content.Error("æ¢ç失败"); |
| | | var newId = StockInfoService.Repository.AddData(newStock); |
| | | if (newId <= 0) return content.Error("æ¢ç失败"); |
| | | |
| | | targetStock = newStock; |
| | | targetStock.Id = newId; |
| | | } |
| | | targetStock = newStock; |
| | | targetStock.Id = newId; |
| | | } |
| | | |
| | | var serialNumbers = stock.Details.Select(d => d.Channel).Distinct().ToList(); |
| | | if (!serialNumbers.Any()) return content.Error("æªæ¾å°ææçåºåå·"); |
| | | var serialNumbers = stock.Details.Select(d => d.Channel).Distinct().ToList(); |
| | | if (!serialNumbers.Any()) return content.Error("æªæ¾å°ææçåºåå·"); |
| | | |
| | | var detailEntities = StockInfoDetailService.Repository.QueryData( |
| | | d => d.StockId == sourceStock.Id && serialNumbers.Contains(d.InboundOrderRowNo)); |
| | | if (!detailEntities.Any()) return content.Error("æªæ¾å°ææçåºåæç»"); |
| | | var detailEntities = StockInfoDetailService.Repository.QueryData( |
| | | d => d.StockId == sourceStock.Id && serialNumbers.Contains(d.InboundOrderRowNo)); |
| | | if (!detailEntities.Any()) return content.Error("æªæ¾å°ææçåºåæç»"); |
| | | |
| | | if (await StockInfoDetail_HtyService.Repository.AddDataAsync(CreateDetailHistory(detailEntities, "æ¢ç")) <= 0) |
| | | return content.Error("æ¢çåå²è®°å½ä¿å失败"); |
| | | if (await StockInfoDetail_HtyService.Repository.AddDataAsync(CreateDetailHistory(detailEntities, "æ¢ç")) <= 0) |
| | | return content.Error("æ¢çåå²è®°å½ä¿å失败"); |
| | | |
| | | if (await StockInfo_HtyService.Repository.AddDataAsync(CreateStockHistory(new[] { sourceStock, targetStock }, "æ¢ç")) <= 0) |
| | | return content.Error("æ¢çåå²è®°å½ä¿å失败"); |
| | | if (await StockInfo_HtyService.Repository.AddDataAsync(CreateStockHistory(new[] { sourceStock, targetStock }, "æ¢ç")) <= 0) |
| | | return content.Error("æ¢çåå²è®°å½ä¿å失败"); |
| | | |
| | | detailEntities.ForEach(d => d.StockId = targetStock.Id); |
| | | var result = await StockInfoDetailService.Repository.UpdateDataAsync(detailEntities); |
| | | if (!result) return content.Error("æ¢ç失败"); |
| | | return content.OK("æ¢çæå"); |
| | | detailEntities.ForEach(d => d.StockId = targetStock.Id); |
| | | var result = await StockInfoDetailService.Repository.UpdateDataAsync(detailEntities); |
| | | if (!result) return content.Error("æ¢ç失败"); |
| | | return content.OK("æ¢çæå"); |
| | | }); |
| | | } |
| | | |
| | | /// <summary> |
| | |
| | | if (stock == null || string.IsNullOrWhiteSpace(stock.SourcePalletNo)) |
| | | return content.Error("æºæçå·ä¸è½ä¸ºç©º"); |
| | | |
| | | var sourceStock = StockInfoService.Repository.QueryFirst(s => s.PalletCode == stock.SourcePalletNo); |
| | | if (sourceStock == null) return content.Error("æºæçä¸åå¨"); |
| | | |
| | | var serialNumbers = stock.Details.Select(d => d.CellBarcode).Distinct().ToList(); |
| | | if (!serialNumbers.Any()) |
| | | return await ExecuteWithinTransactionAsync(async () => |
| | | { |
| | | serialNumbers = sourceStock.Details |
| | | .Where(x => stock.Details.Any(d => d.Channel == x.InboundOrderRowNo)) |
| | | .Select(x => x.SerialNumber) |
| | | .ToList(); |
| | | } |
| | | var sourceStock = StockInfoService.Repository.QueryFirst(s => s.PalletCode == stock.SourcePalletNo); |
| | | if (sourceStock == null) return content.Error("æºæçä¸åå¨"); |
| | | |
| | | var detailEntities = StockInfoDetailService.Repository.QueryData( |
| | | d => d.StockId == sourceStock.Id && serialNumbers.Contains(d.SerialNumber)); |
| | | if (!detailEntities.Any()) return content.Error("æªæ¾å°ææçåºåæç»"); |
| | | var serialNumbers = stock.Details.Select(d => d.CellBarcode).Distinct().ToList(); |
| | | if (!serialNumbers.Any()) |
| | | { |
| | | serialNumbers = sourceStock.Details |
| | | .Where(x => stock.Details.Any(d => d.Channel == x.InboundOrderRowNo)) |
| | | .Select(x => x.SerialNumber) |
| | | .ToList(); |
| | | } |
| | | |
| | | if (await StockInfoDetail_HtyService.Repository.AddDataAsync(CreateDetailHistory(detailEntities, "æç")) <= 0) |
| | | return content.Error("æçåå²è®°å½ä¿å失败"); |
| | | var detailEntities = StockInfoDetailService.Repository.QueryData( |
| | | d => d.StockId == sourceStock.Id && serialNumbers.Contains(d.SerialNumber)); |
| | | if (!detailEntities.Any()) return content.Error("æªæ¾å°ææçåºåæç»"); |
| | | |
| | | if (await StockInfo_HtyService.Repository.AddDataAsync(CreateStockHistory(new[] { sourceStock }, "æç")) <= 0) |
| | | return content.Error("æçåå²è®°å½ä¿å失败"); |
| | | if (await StockInfoDetail_HtyService.Repository.AddDataAsync(CreateDetailHistory(detailEntities, "æç")) <= 0) |
| | | return content.Error("æçåå²è®°å½ä¿å失败"); |
| | | |
| | | var result = await StockInfoDetailService.Repository.DeleteDataAsync(detailEntities); |
| | | if (!result) return content.Error("æç失败"); |
| | | return content.OK("æçæå"); |
| | | if (await StockInfo_HtyService.Repository.AddDataAsync(CreateStockHistory(new[] { sourceStock }, "æç")) <= 0) |
| | | return content.Error("æçåå²è®°å½ä¿å失败"); |
| | | |
| | | var result = await StockInfoDetailService.Repository.DeleteDataAsync(detailEntities); |
| | | if (!result) return content.Error("æç失败"); |
| | | return content.OK("æçæå"); |
| | | }); |
| | | } |
| | | |
| | | /// <summary> |
| | |
| | | } |
| | | } |
| | | |
| | | public object x_GetTreeItem(int menuId) |
| | | { |
| | | var sysMenu = BaseDal.QueryData(x => x.MenuId == menuId) |
| | | .Select( |
| | | p => new |
| | | { |
| | | p.MenuId, |
| | | p.ParentId, |
| | | p.MenuName, |
| | | p.Url, |
| | | p.Auth, |
| | | p.OrderNo, |
| | | p.Icon, |
| | | p.Enable, |
| | | // 2022.03.26å¢ç§»å¨ç«¯å èåç±»å |
| | | MenuType = p.MenuType, |
| | | p.CreateDate, |
| | | p.Creater, |
| | | p.TableName, |
| | | p.ModifyDate |
| | | }).FirstOrDefault(); |
| | | return sysMenu; |
| | | } |
| | | |
| | | /// <summary> |
| | | /// ç¼è¾èåæ¶ï¼è·åèåä¿¡æ¯ |
| | | /// </summary> |
| | |
| | | /// <returns></returns> |
| | | public object GetTreeItem(int menuId) |
| | | { |
| | | return GetTreeItem(menuId); |
| | | return x_GetTreeItem(menuId); |
| | | } |
| | | |
| | | /// <summary> |
| | |
| | | { |
| | | try |
| | | { |
| | | WebResponseContent content = await GetTasksByPalletCodeAsync(taskDto.PalletCode); |
| | | WebResponseContent content = await GetTaskByPalletCodeAsync(taskDto.PalletCode); |
| | | if (content.Status) |
| | | { |
| | | return content; |
| | |
| | | var locationInfo = await _locationInfoService.GetLocationInfo(task.Roadway); |
| | | if (locationInfo == null) return WebResponseContent.Instance.Error("æªæ¾å°å¯¹åºçè´§ä½"); |
| | | |
| | | locationInfo.LocationStatus = LocationStatusEnum.FreeLock.GetHashCode(); |
| | | task.CurrentAddress = task.SourceAddress; |
| | | task.NextAddress = locationInfo.LocationCode; |
| | | task.TargetAddress = locationInfo.LocationCode; |
| | | task.TaskStatus = TaskInStatusEnum.Line_InFinish.GetHashCode(); |
| | | return await ExecuteWithinTransactionAsync(async () => |
| | | { |
| | | locationInfo.LocationStatus = LocationStatusEnum.FreeLock.GetHashCode(); |
| | | task.CurrentAddress = task.SourceAddress; |
| | | task.NextAddress = locationInfo.LocationCode; |
| | | task.TargetAddress = locationInfo.LocationCode; |
| | | task.TaskStatus = TaskInStatusEnum.Line_InFinish.GetHashCode(); |
| | | |
| | | var updateResult = await BaseDal.UpdateDataAsync(task); |
| | | var locationResult = await _locationInfoService.UpdateLocationInfoAsync(locationInfo); |
| | | var updateTaskResult = await BaseDal.UpdateDataAsync(task); |
| | | var updateLocationResult = await _locationInfoService.UpdateLocationInfoAsync(locationInfo); |
| | | if (!updateTaskResult || !updateLocationResult) |
| | | { |
| | | return WebResponseContent.Instance.Error("任塿´æ°å¤±è´¥"); |
| | | } |
| | | |
| | | return WebResponseContent.Instance.OK( |
| | | updateResult && locationResult ? "任塿´æ°æå" : "任塿´æ°å¤±è´¥", |
| | | locationInfo.LocationCode); |
| | | return WebResponseContent.Instance.OK("任塿´æ°æå", locationInfo.LocationCode); |
| | | }); |
| | | } |
| | | catch (Exception ex) |
| | | { |
| | |
| | | if (location == null) return WebResponseContent.Instance.Error("æªæ¾å°å¯¹åºçè´§ä½"); |
| | | |
| | | var stockInfo = await _stockInfoService.GetStockInfoAsync(taskDto.PalletCode); |
| | | stockInfo.LocationCode = location.LocationCode; |
| | | stockInfo.LocationId = location.Id; |
| | | stockInfo.OutboundDate = task.Roadway switch |
| | | if (stockInfo == null) return WebResponseContent.Instance.Error("æªæ¾å°å¯¹åºåºåä¿¡æ¯"); |
| | | |
| | | return await ExecuteWithinTransactionAsync(async () => |
| | | { |
| | | var r when r.Contains("GW") => DateTime.Now.AddHours(2), |
| | | var r when r.Contains("CW") => DateTime.Now.AddHours(1), |
| | | _ => DateTime.Now |
| | | }; |
| | | stockInfo.StockStatus = StockStatusEmun.å
¥åºå®æ.GetHashCode(); |
| | | stockInfo.LocationCode = location.LocationCode; |
| | | stockInfo.LocationId = location.Id; |
| | | stockInfo.OutboundDate = task.Roadway switch |
| | | { |
| | | var r when r.Contains("GW") => DateTime.Now.AddHours(2), |
| | | var r when r.Contains("CW") => DateTime.Now.AddHours(1), |
| | | _ => DateTime.Now |
| | | }; |
| | | stockInfo.StockStatus = StockStatusEmun.å
¥åºå®æ.GetHashCode(); |
| | | |
| | | location.LocationStatus = LocationStatusEnum.InStock.GetHashCode(); |
| | | location.LocationStatus = LocationStatusEnum.InStock.GetHashCode(); |
| | | |
| | | var updateLocationResult = await _locationInfoService.UpdateLocationInfoAsync(location); |
| | | var updateStockResult = await _stockInfoService.UpdateStockAsync(stockInfo); |
| | | if (!updateLocationResult || !updateStockResult) |
| | | return WebResponseContent.Instance.Error("ä»»å¡å®æå¤±è´¥"); |
| | | return await CompleteTaskAsync(task); |
| | | var updateLocationResult = await _locationInfoService.UpdateLocationInfoAsync(location); |
| | | var updateStockResult = await _stockInfoService.UpdateStockAsync(stockInfo); |
| | | if (!updateLocationResult || !updateStockResult) |
| | | return WebResponseContent.Instance.Error("ä»»å¡å®æå¤±è´¥"); |
| | | return await CompleteTaskAsync(task); |
| | | }); |
| | | } |
| | | catch (Exception ex) |
| | | { |
| | |
| | | var location = await _locationInfoService.GetLocationInfo(task.Roadway, task.SourceAddress); |
| | | if (location == null) return WebResponseContent.Instance.Error("æªæ¾å°å¯¹åºçè´§ä½"); |
| | | |
| | | var stockInfo = await _stockInfoService.GetStockInfoAsync(taskDto.PalletCode); |
| | | stockInfo.LocationId = 0; |
| | | stockInfo.LocationCode = null; |
| | | stockInfo.OutboundDate = DateTime.Now; |
| | | var stockInfo = await _stockInfoService.GetStockInfoAsync(taskDto.PalletCode); |
| | | if (stockInfo == null) return WebResponseContent.Instance.Error("æªæ¾å°å¯¹åºåºåä¿¡æ¯"); |
| | | |
| | | location.LocationStatus = LocationStatusEnum.Free.GetHashCode(); |
| | | return await ExecuteWithinTransactionAsync(async () => |
| | | { |
| | | stockInfo.LocationId = 0; |
| | | stockInfo.LocationCode = null; |
| | | stockInfo.OutboundDate = DateTime.Now; |
| | | |
| | | var updateLocationResult = await _locationInfoService.UpdateLocationInfoAsync(location); |
| | | var updateStockResult = await _stockInfoService.UpdateStockAsync(stockInfo); |
| | | if (!updateLocationResult || !updateStockResult) |
| | | return WebResponseContent.Instance.Error("ä»»å¡å®æå¤±è´¥"); |
| | | return await CompleteTaskAsync(task); |
| | | location.LocationStatus = LocationStatusEnum.Free.GetHashCode(); |
| | | |
| | | var updateLocationResult = await _locationInfoService.UpdateLocationInfoAsync(location); |
| | | var updateStockResult = await _stockInfoService.UpdateStockAsync(stockInfo); |
| | | if (!updateLocationResult || !updateStockResult) |
| | | return WebResponseContent.Instance.Error("ä»»å¡å®æå¤±è´¥"); |
| | | return await CompleteTaskAsync(task); |
| | | }); |
| | | } |
| | | catch (Exception ex) |
| | | { |
| | |
| | | var stockInfo = await _stockInfoService.GetStockInfoAsync(taskDto.PalletCode); |
| | | if (stockInfo == null) return WebResponseContent.Instance.Error("æªæ¾å°å¯¹åºåºåä¿¡æ¯"); |
| | | |
| | | stockInfo.LocationCode = targetLocation.LocationCode; |
| | | stockInfo.LocationId = targetLocation.Id; |
| | | stockInfo.StockStatus = StockStatusEmun.å
¥åºå®æ.GetHashCode(); |
| | | return await ExecuteWithinTransactionAsync(async () => |
| | | { |
| | | stockInfo.LocationCode = targetLocation.LocationCode; |
| | | stockInfo.LocationId = targetLocation.Id; |
| | | stockInfo.StockStatus = StockStatusEmun.å
¥åºå®æ.GetHashCode(); |
| | | |
| | | sourceLocation.LocationStatus = LocationStatusEnum.Free.GetHashCode(); |
| | | targetLocation.LocationStatus = LocationStatusEnum.InStock.GetHashCode(); |
| | | sourceLocation.LocationStatus = LocationStatusEnum.Free.GetHashCode(); |
| | | targetLocation.LocationStatus = LocationStatusEnum.InStock.GetHashCode(); |
| | | |
| | | var updateSourceResult = await _locationInfoService.UpdateLocationInfoAsync(sourceLocation); |
| | | var updateTargetResult = await _locationInfoService.UpdateLocationInfoAsync(targetLocation); |
| | | var updateStockResult = await _stockInfoService.UpdateStockAsync(stockInfo); |
| | | var updateSourceResult = await _locationInfoService.UpdateLocationInfoAsync(sourceLocation); |
| | | var updateTargetResult = await _locationInfoService.UpdateLocationInfoAsync(targetLocation); |
| | | var updateStockResult = await _stockInfoService.UpdateStockAsync(stockInfo); |
| | | |
| | | if (!updateSourceResult || !updateTargetResult || !updateStockResult) |
| | | return WebResponseContent.Instance.Error("ç§»åºä»»å¡å®æå¤±è´¥"); |
| | | if (!updateSourceResult || !updateTargetResult || !updateStockResult) |
| | | return WebResponseContent.Instance.Error("ç§»åºä»»å¡å®æå¤±è´¥"); |
| | | |
| | | return await CompleteTaskAsync(task); |
| | | return await CompleteTaskAsync(task); |
| | | }); |
| | | } |
| | | catch (Exception ex) |
| | | { |
| | |
| | | { |
| | | try |
| | | { |
| | | WebResponseContent content = await GetTasksByPalletCodeAsync(taskDto.PalletCode); |
| | | WebResponseContent content = await GetTaskByPalletCodeAsync(taskDto.PalletCode); |
| | | if (content.Status) |
| | | { |
| | | return content; |
| | |
| | | }; |
| | | var taskDtos = task.Adapt<WMSTaskDTO>(); |
| | | |
| | | BaseDal.AddData(task); |
| | | return WebResponseContent.Instance.OK("æ¥è¯¢æå", taskDtos); |
| | | var addResult = await BaseDal.AddDataAsync(task); |
| | | if (!addResult) |
| | | return WebResponseContent.Instance.Error("ä»»å¡å建失败"); |
| | | return WebResponseContent.Instance.OK("ä»»å¡å建æå", taskDtos); |
| | | } |
| | | catch (Exception ex) |
| | | { |
| | |
| | | /// </summary> |
| | | /// <param name="palletCode"></param> |
| | | /// <returns></returns> |
| | | private async Task<WebResponseContent> GetTasksByPalletCodeAsync(string palletCode) |
| | | private async Task<WebResponseContent> GetTaskByPalletCodeAsync(string palletCode) |
| | | { |
| | | try |
| | | { |
| | | var tasks = await BaseDal.QueryFirstAsync(s => s.PalletCode == palletCode); |
| | | if (tasks == null) |
| | | var task = await BaseDal.QueryFirstAsync(s => s.PalletCode == palletCode); |
| | | if (task == null) |
| | | return WebResponseContent.Instance.Error("æªæ¾å°å¯¹åºçä»»å¡"); |
| | | var taskDtos = _mapper.Map<List<WMSTaskDTO>>(tasks); |
| | | return WebResponseContent.Instance.OK("æ¥è¯¢æå", taskDtos); |
| | | var taskDto = _mapper.Map<WMSTaskDTO>(task); |
| | | return WebResponseContent.Instance.OK("æ¥è¯¢æå", taskDto); |
| | | } |
| | | catch (Exception ex) |
| | | { |
| | |
| | | taskList.Add(task); |
| | | } |
| | | |
| | | var addResult = await BaseDal.AddDataAsync(taskList) > 0; |
| | | if (!addResult) |
| | | var transactionResult = await ExecuteWithinTransactionAsync(async () => |
| | | { |
| | | return WebResponseContent.Instance.Error($"æ¹éå建任å¡å¤±è´¥ï¼å
± {taskList.Count} 个任å¡"); |
| | | } |
| | | |
| | | // ä»»å¡å建æååï¼åæ¥éå®åºååè´§ä½ç¶æï¼é¿å
éå¤åé
|
| | | var stocksToUpdate = stocksToProcess |
| | | .Select(s => |
| | | var addResult = await BaseDal.AddDataAsync(taskList) > 0; |
| | | if (!addResult) |
| | | { |
| | | s.StockStatus = StockStatusEmun.åºåºéå®.GetHashCode(); |
| | | return s; |
| | | }) |
| | | .ToList(); |
| | | |
| | | var updateStockResult = await _stockInfoService.Repository.UpdateDataAsync(stocksToUpdate); |
| | | if (!updateStockResult) |
| | | { |
| | | return WebResponseContent.Instance.Error($"ä»»å¡å建æåï¼ä½åºåç¶ææ´æ°å¤±è´¥ï¼å
± {stocksToUpdate.Count} æ¡"); |
| | | } |
| | | |
| | | var locationsToUpdate = stocksToProcess |
| | | .Where(s => s.LocationDetails != null) |
| | | .GroupBy(s => s.LocationDetails.Id) |
| | | .Select(g => |
| | | { |
| | | var location = g.First().LocationDetails; |
| | | location.LocationStatus = LocationStatusEnum.InStockLock.GetHashCode(); |
| | | return location; |
| | | }) |
| | | .ToList(); |
| | | |
| | | if (locationsToUpdate.Any()) |
| | | { |
| | | var updateLocationResult = await _locationInfoService.Repository.UpdateDataAsync(locationsToUpdate); |
| | | if (!updateLocationResult) |
| | | { |
| | | return WebResponseContent.Instance.Error($"ä»»å¡å建æåï¼ä½è´§ä½ç¶ææ´æ°å¤±è´¥ï¼å
± {locationsToUpdate.Count} æ¡"); |
| | | return WebResponseContent.Instance.Error($"æ¹éå建任å¡å¤±è´¥ï¼å
± {taskList.Count} 个任å¡"); |
| | | } |
| | | |
| | | // ä»»å¡å建æååï¼åæ¥éå®åºååè´§ä½ç¶æï¼é¿å
éå¤åé
|
| | | var stocksToUpdate = stocksToProcess |
| | | .Select(s => |
| | | { |
| | | s.StockStatus = StockStatusEmun.åºåºéå®.GetHashCode(); |
| | | return s; |
| | | }) |
| | | .ToList(); |
| | | |
| | | var updateStockResult = await _stockInfoService.Repository.UpdateDataAsync(stocksToUpdate); |
| | | if (!updateStockResult) |
| | | { |
| | | return WebResponseContent.Instance.Error($"ä»»å¡å建æåï¼ä½åºåç¶ææ´æ°å¤±è´¥ï¼å
± {stocksToUpdate.Count} æ¡"); |
| | | } |
| | | |
| | | var locationsToUpdate = stocksToProcess |
| | | .Where(s => s.LocationDetails != null) |
| | | .GroupBy(s => s.LocationDetails.Id) |
| | | .Select(g => |
| | | { |
| | | var location = g.First().LocationDetails; |
| | | location.LocationStatus = LocationStatusEnum.InStockLock.GetHashCode(); |
| | | return location; |
| | | }) |
| | | .ToList(); |
| | | |
| | | if (locationsToUpdate.Any()) |
| | | { |
| | | var updateLocationResult = await _locationInfoService.Repository.UpdateDataAsync(locationsToUpdate); |
| | | if (!updateLocationResult) |
| | | { |
| | | return WebResponseContent.Instance.Error($"ä»»å¡å建æåï¼ä½è´§ä½ç¶ææ´æ°å¤±è´¥ï¼å
± {locationsToUpdate.Count} æ¡"); |
| | | } |
| | | } |
| | | |
| | | return WebResponseContent.Instance.OK(); |
| | | }); |
| | | if (!transactionResult.Status) |
| | | { |
| | | return transactionResult; |
| | | } |
| | | |
| | | // 6. éç¥ WCSï¼å¼æ¥ï¼ä¸å½±å主æµç¨ï¼ |
| | |
| | | try |
| | | { |
| | | var stockInfo = await _stockInfoService.GetStockInfoAsync(input.PalletCode, input.LocationCode); |
| | | |
| | | int locationStatus; |
| | | if (stockInfo == null) |
| | | { |
| | | var location = await _locationInfoService.GetLocationInfoAsync(input.LocationCode); |
| | | |
| | | OutputDto outPutDto = new OutputDto() |
| | | { |
| | | LocationCode = input.LocationCode, |
| | | PalletCode = input.PalletCode, |
| | | IsNormalProcedure = 1, |
| | | LocationStatus = location.LocationStatus |
| | | }; |
| | | content.OK(data: outPutDto); |
| | | locationStatus = location?.LocationStatus ?? 0; |
| | | } |
| | | else |
| | | { |
| | | OutputDto outPutDto = new OutputDto() |
| | | { |
| | | LocationCode = input.LocationCode, |
| | | PalletCode = input.PalletCode, |
| | | IsNormalProcedure = 1, |
| | | LocationStatus = stockInfo.LocationDetails.LocationStatus |
| | | }; |
| | | content.OK(data: outPutDto); |
| | | locationStatus = stockInfo.LocationDetails?.LocationStatus ?? 0; |
| | | } |
| | | |
| | | OutputDto outPutDto = new OutputDto() |
| | | { |
| | | LocationCode = input.LocationCode, |
| | | PalletCode = input.PalletCode, |
| | | IsNormalProcedure = 1, |
| | | LocationStatus = locationStatus |
| | | }; |
| | | return content.OK(data: outPutDto); |
| | | } |
| | | catch (Exception ex) |
| | | { |
| | |
| | | using System.Reflection; |
| | | using System.Text; |
| | | using Autofac; |
| | | using Autofac.Core; |
| | | using Autofac.Extensions.DependencyInjection; |
| | |
| | | using Newtonsoft.Json.Converters; |
| | | using Newtonsoft.Json.Serialization; |
| | | using Serilog; |
| | | using Serilog.Formatting.Json; |
| | | using System.Reflection; |
| | | using System.Text; |
| | | using WIDESEA_Core; |
| | | using WIDESEA_Core.Authorization; |
| | | using WIDESEA_Core.BaseServices; |
| | |
| | | loggerConfiguration |
| | | .ReadFrom.Configuration(context.Configuration) |
| | | .ReadFrom.Services(services) |
| | | .Enrich.FromLogContext() |
| | | .WriteTo.Console() |
| | | //.Enrich.FromLogContext() |
| | | .WriteTo.Console(outputTemplate: "[{Timestamp:HH:mm:ss} {Level:u3}] {Message:lj}{NewLine}{Exception}") |
| | | .WriteTo.File( |
| | | "logs/serilog-.log.txt", |
| | | //new JsonFormatter(renderMessage: true), |
| | | "logs/serilog-.log", |
| | | outputTemplate: "[{Timestamp:HH:mm:ss} {Level:u3}] {Message:lj}{NewLine}{Exception}", |
| | | rollingInterval: RollingInterval.Day, |
| | | retainedFileCountLimit: 30, |
| | | shared: true); |
| | | // æ¯ä¸ªæ¥å¿æä»¶æå¤§å¤§å°ï¼åèï¼ï¼æ¤å¤è®¾ç½®ä¸º10MB |
| | | fileSizeLimitBytes: 10 * 1024 * 1024, |
| | | shared: true |
| | | ) |
| | | // 6. å¯éï¼è¾åºå°Seqæ¥å¿æå¡å¨ï¼ç»æåæ¥å¿æå¡å¨ï¼ |
| | | // éè¦å®è£
Serilog.Sinks.Seq NuGetå
ï¼å¹¶ç¡®ä¿Seqæå¡å¨ http://localhost:5341 è¿è¡ |
| | | // å¦ä¸éè¦Seqæ¥å¿ï¼æ³¨éæä¸æ¹ä»£ç å³å¯ |
| | | .WriteTo.Seq( |
| | | serverUrl: "http://localhost:5341", |
| | | apiKey: "CWVa8UWQ9CdUp9GWXCPL", // å¦Seqéè¦ApiKeyåé
ç½®çå®å¯é¥ |
| | | batchPostingLimit: 1000, // æ¹éåéæ°é |
| | | period: TimeSpan.FromSeconds(2) // åéé´é |
| | | ); |
| | | }); |
| | | builder.ConfigureApplication(); |
| | | |
| | |
| | | <PackageReference Include="Serilog.AspNetCore" Version="8.0.1" /> |
| | | <PackageReference Include="Serilog.Settings.Configuration" Version="8.0.0" /> |
| | | <PackageReference Include="Serilog.Sinks.Console" Version="5.0.1" /> |
| | | <PackageReference Include="Serilog.Sinks.File" Version="5.0.0" /> |
| | | <PackageReference Include="Serilog.Sinks.File" Version="6.0.0" /> |
| | | <PackageReference Include="Serilog.Sinks.Seq" Version="9.0.0" /> |
| | | <PackageReference Include="Swashbuckle.AspNetCore.Annotations" Version="6.7.3" /> |
| | | </ItemGroup> |
| | | |
| | |
| | | <CopyToOutputDirectory>Always</CopyToOutputDirectory> |
| | | </Content> |
| | | </ItemGroup> |
| | | |
| | | <ItemGroup> |
| | | <Folder Include="logs\" /> |
| | | </ItemGroup> |
| | | </Project> |
| | |
| | | { |
| | | "urls": "http://*:9291", //webæå¡ç«¯å£ï¼å¦æç¨IISé¨ç½²ï¼æè¿ä¸ªå»æ |
| | | "Serilog": { |
| | | "MinimumLevel": { |
| | | "Default": "Information", |
| | | "Override": { |
| | | "Microsoft": "Information", |
| | | "Microsoft.AspNetCore": "Warning", |
| | | "Microsoft.AspNetCore.Routing": "Warning", |
| | | "Microsoft.AspNetCore.Mvc": "Warning", |
| | | "Microsoft.AspNetCore.Mvc.Infrastructure": "Warning", |
| | | "Microsoft.AspNetCore.Mvc.Filters": "Warning", |
| | | "Microsoft.AspNetCore.Mvc.ModelBinding": "Warning", |
| | | "Microsoft.EntityFrameworkCore": "Warning" |
| | | } |
| | | } |
| | | }, |
| | | "Logging": { |
| | | "LogLevel": { |
| | | "Default": "Information", |
| | | "Microsoft": "Warning", |
| | | "Microsoft.AspNetCore": "Warning", |
| | | "Microsoft.AspNetCore.DataProtection": "Warning" |
| | | "Microsoft.AspNetCore.DataProtection": "Warning", |
| | | "Microsoft.AspNetCore.Routing": "Warning", |
| | | "Microsoft.AspNetCore.Mvc": "Warning", |
| | | "Microsoft.AspNetCore.Mvc.Infrastructure": "Warning", |
| | | "Microsoft.AspNetCore.Mvc.Filters": "Warning", |
| | | "Microsoft.AspNetCore.Mvc.ModelBinding": "Warning" |
| | | } |
| | | }, |
| | | "dics": "inOrderType,outOrderType,inboundState,createType,enableEnum,enableStatusEnum,locationStatusEnum,locationTypeEnum,taskTypeEnum,taskStatusEnum,outboundStatusEnum,orderDetailStatusEnum,stockStatusEmun,stockChangeType,outStockStatus,receiveOrderTypeEnum,authorityScope,authorityScopes,locationChangeType,warehouses,suppliers,taskType,receiveStatus,purchaseType,purchaseOrderStatus,printStatus", |
| | |
| | | // 注æï¼http://127.0.0.1:1818 å http://localhost:1818 æ¯ä¸ä¸æ ·ç |
| | | "IPs": "http://127.0.0.1:8080,http://localhost:8080,http://127.0.0.1:8081,http://localhost:8081" |
| | | }, |
| | | |
| | | "LocalLogConfig": { |
| | | "LogLevel": "DEBUG", //æ¥å¿çº§å« DEBUG,INFO,WARN,ERROR,FATAL |
| | | "LogFileSize": 10, //å个æ¥å¿æä»¶å¤§å°ï¼åä½MB |
| | | "LogFileCount": 300, //æ¥å¿æä»¶æ°é |
| | | "EnableConsoleOutput": false, //æ¯å¦è¾åºå°æ§å¶å° |
| | | "EnableFloderByLevel": true //æ¯å¦ææ¥å¿çº§å«çæä¸åçæä»¶å¤¹ |
| | | }, |
| | | "LogAopEnable": false, |
| | | "PrintSql": false, //æå°SQLè¯å¥ |
| | | "ApiName": "WIDESEA", |