diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..1ff0c42 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,63 @@ +############################################################################### +# Set default behavior to automatically normalize line endings. +############################################################################### +* text=auto + +############################################################################### +# Set default behavior for command prompt diff. +# +# This is need for earlier builds of msysgit that does not have it on by +# default for csharp files. +# Note: This is only used by command line +############################################################################### +#*.cs diff=csharp + +############################################################################### +# Set the merge driver for project and solution files +# +# Merging from the command prompt will add diff markers to the files if there +# are conflicts (Merging from VS is not affected by the settings below, in VS +# the diff markers are never inserted). Diff markers may cause the following +# file extensions to fail to load in VS. An alternative would be to treat +# these files as binary and thus will always conflict and require user +# intervention with every merge. To do so, just uncomment the entries below +############################################################################### +#*.sln merge=binary +#*.csproj merge=binary +#*.vbproj merge=binary +#*.vcxproj merge=binary +#*.vcproj merge=binary +#*.dbproj merge=binary +#*.fsproj merge=binary +#*.lsproj merge=binary +#*.wixproj merge=binary +#*.modelproj merge=binary +#*.sqlproj merge=binary +#*.wwaproj merge=binary + +############################################################################### +# behavior for image files +# +# image files are treated as binary by default. +############################################################################### +#*.jpg binary +#*.png binary +#*.gif binary + +############################################################################### +# diff behavior for common document formats +# +# Convert binary document formats to text before diffing them. This feature +# is only available from the command line. Turn it on by uncommenting the +# entries below. +############################################################################### +#*.doc diff=astextplain +#*.DOC diff=astextplain +#*.docx diff=astextplain +#*.DOCX diff=astextplain +#*.dot diff=astextplain +#*.DOT diff=astextplain +#*.pdf diff=astextplain +#*.PDF diff=astextplain +#*.rtf diff=astextplain +#*.RTF diff=astextplain diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..d8abe29 --- /dev/null +++ b/.gitignore @@ -0,0 +1,344 @@ +## Ignore Visual Studio temporary files, build results, and +## files generated by popular Visual Studio add-ons. +## +## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore + +# User-specific files +*.rsuser +*.suo +*.user +*.userosscache +*.sln.docstates + +# User-specific files (MonoDevelop/Xamarin Studio) +*.userprefs + +# Build results +[Dd]ebug/ +[Dd]ebugPublic/ +[Rr]elease/ +[Rr]eleases/ +x64/ +x86/ +[Aa][Rr][Mm]/ +[Aa][Rr][Mm]64/ +bld/ +[Bb]in/ +[Oo]bj/ +[Ll]og/ + +# Visual Studio 2015/2017 cache/options directory +.vs/ +# Uncomment if you have tasks that create the project's static files in wwwroot +#wwwroot/ + +# Visual Studio 2017 auto generated files +Generated\ Files/ + +# MSTest test Results +[Tt]est[Rr]esult*/ +[Bb]uild[Ll]og.* + +# NUNIT +*.VisualState.xml +TestResult.xml + +# Build Results of an ATL Project +[Dd]ebugPS/ +[Rr]eleasePS/ +dlldata.c + +# Benchmark Results +BenchmarkDotNet.Artifacts/ + +# .NET Core +project.lock.json +project.fragment.lock.json +artifacts/ + +# StyleCop +StyleCopReport.xml + +# Files built by Visual Studio +*_i.c +*_p.c +*_h.h +*.ilk +*.meta +*.obj +*.iobj +*.pch +*.pdb +*.ipdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.tmp_proj +*_wpftmp.csproj +*.log +*.vspscc +*.vssscc +.builds +*.pidb +*.svclog +*.scc + +# Chutzpah Test files +_Chutzpah* + +# Visual C++ cache files +ipch/ +*.aps +*.ncb +*.opendb +*.opensdf +*.sdf +*.cachefile +*.VC.db +*.VC.VC.opendb + +# Visual Studio profiler +*.psess +*.vsp +*.vspx +*.sap + +# Visual Studio Trace Files +*.e2e + +# TFS 2012 Local Workspace +$tf/ + +# Guidance Automation Toolkit +*.gpState + +# ReSharper is a .NET coding add-in +_ReSharper*/ +*.[Rr]e[Ss]harper +*.DotSettings.user + +# JustCode is a .NET coding add-in +.JustCode + +# TeamCity is a build add-in +_TeamCity* + +# DotCover is a Code Coverage Tool +*.dotCover + +# AxoCover is a Code Coverage Tool +.axoCover/* +!.axoCover/settings.json + +# Visual Studio code coverage results +*.coverage +*.coveragexml + +# NCrunch +_NCrunch_* +.*crunch*.local.xml +nCrunchTemp_* + +# MightyMoose +*.mm.* +AutoTest.Net/ + +# Web workbench (sass) +.sass-cache/ + +# Installshield output folder +[Ee]xpress/ + +# DocProject is a documentation generator add-in +DocProject/buildhelp/ +DocProject/Help/*.HxT +DocProject/Help/*.HxC +DocProject/Help/*.hhc +DocProject/Help/*.hhk +DocProject/Help/*.hhp +DocProject/Help/Html2 +DocProject/Help/html + +# Click-Once directory +publish/ + +# Publish Web Output +*.[Pp]ublish.xml +*.azurePubxml +# Note: Comment the next line if you want to checkin your web deploy settings, +# but database connection strings (with potential passwords) will be unencrypted +*.pubxml +*.publishproj + +# Microsoft Azure Web App publish settings. Comment the next line if you want to +# checkin your Azure Web App publish settings, but sensitive information contained +# in these scripts will be unencrypted +PublishScripts/ + +# NuGet Packages +*.nupkg +# The packages folder can be ignored because of Package Restore +**/[Pp]ackages/* +# except build/, which is used as an MSBuild target. +!**/[Pp]ackages/build/ +# Uncomment if necessary however generally it will be regenerated when needed +#!**/[Pp]ackages/repositories.config +# NuGet v3's project.json files produces more ignorable files +*.nuget.props +*.nuget.targets + +# Microsoft Azure Build Output +csx/ +*.build.csdef + +# Microsoft Azure Emulator +ecf/ +rcf/ + +# Windows Store app package directories and files +AppPackages/ +BundleArtifacts/ +Package.StoreAssociation.xml +_pkginfo.txt +*.appx + +# Visual Studio cache files +# files ending in .cache can be ignored +*.[Cc]ache +# but keep track of directories ending in .cache +!?*.[Cc]ache/ + +# Others +ClientBin/ +~$* +*~ +*.dbmdl +*.dbproj.schemaview +*.jfm +*.pfx +*.publishsettings +orleans.codegen.cs + +# Including strong name files can present a security risk +# (https://github.com/github/gitignore/pull/2483#issue-259490424) +#*.snk + +# Since there are multiple workflows, uncomment next line to ignore bower_components +# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) +#bower_components/ + +# RIA/Silverlight projects +Generated_Code/ + +# Backup & report files from converting an old project file +# to a newer Visual Studio version. Backup files are not needed, +# because we have git ;-) +_UpgradeReport_Files/ +Backup*/ +UpgradeLog*.XML +UpgradeLog*.htm +ServiceFabricBackup/ +*.rptproj.bak + +# SQL Server files +*.mdf +*.ldf +*.ndf + +# Business Intelligence projects +*.rdl.data +*.bim.layout +*.bim_*.settings +*.rptproj.rsuser +*- Backup*.rdl + +# Microsoft Fakes +FakesAssemblies/ + +# GhostDoc plugin setting file +*.GhostDoc.xml + +# Node.js Tools for Visual Studio +.ntvs_analysis.dat +node_modules/ + +# Visual Studio 6 build log +*.plg + +# Visual Studio 6 workspace options file +*.opt + +# Visual Studio 6 auto-generated workspace file (contains which files were open etc.) +*.vbw + +# Visual Studio LightSwitch build output +**/*.HTMLClient/GeneratedArtifacts +**/*.DesktopClient/GeneratedArtifacts +**/*.DesktopClient/ModelManifest.xml +**/*.Server/GeneratedArtifacts +**/*.Server/ModelManifest.xml +_Pvt_Extensions + +# Paket dependency manager +.paket/paket.exe +paket-files/ + +# FAKE - F# Make +.fake/ + +# JetBrains Rider +.idea/ +*.sln.iml + +# CodeRush personal settings +.cr/personal + +# Python Tools for Visual Studio (PTVS) +__pycache__/ +*.pyc + +# Cake - Uncomment if you are using it +# tools/** +# !tools/packages.config + +# Tabs Studio +*.tss + +# Telerik's JustMock configuration file +*.jmconfig + +# BizTalk build output +*.btp.cs +*.btm.cs +*.odx.cs +*.xsd.cs + +# OpenCover UI analysis results +OpenCover/ + +# Azure Stream Analytics local run output +ASALocalRun/ + +# MSBuild Binary and Structured Log +*.binlog + +# NVidia Nsight GPU debugger configuration file +*.nvuser + +# MFractors (Xamarin productivity tool) working folder +.mfractor/ + +# Local History for Visual Studio +.localhistory/ + +# BeatPulse healthcheck temp database +healthchecksdb + +appsettings.demo.json +/src/Khd.Core.Wcs/appsettings.json +/src/Khd.Core.Wpf/appsettings.json diff --git a/Khd.Core.Api.sln b/Khd.Core.Api.sln new file mode 100644 index 0000000..c890fe4 --- /dev/null +++ b/Khd.Core.Api.sln @@ -0,0 +1,85 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.3.32929.385 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Khd.Core.Api", "src\Khd.Core.Api\Khd.Core.Api.csproj", "{51C310CD-5D5C-49AF-A823-05743DFA84F9}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Khd.Core.EntityFramework", "src\Khd.Core.EntityFramework\Khd.Core.EntityFramework.csproj", "{44DF5518-A298-4B86-9169-6119ADF39B2D}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Khd.Core.Domain", "src\Khd.Core.Domain\Khd.Core.Domain.csproj", "{BAF46618-412D-4515-B4F5-D5F7BFE2ED7C}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Khd.Core.Library", "src\Khd.Core.Library\Khd.Core.Library.csproj", "{CA8E36B3-560A-49AB-A51B-491879312E48}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Khd.Core.Application", "src\Khd.Core.Application\Khd.Core.Application.csproj", "{B1981F15-21AD-4340-8818-36BB1AAA7E3D}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Khd.Core.Plc", "src\Khd.Core.Plc\Khd.Core.Plc.csproj", "{68C935C1-3FC2-42B2-A2CB-F1D4D3A8C507}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Khd.Core.Wcs", "src\Khd.Core.Wcs\Khd.Core.Wcs.csproj", "{D924C4A2-85D6-46D1-86E0-CEBF66F897FD}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Khd.Core.Thrift", "src\Khd.Core.Thrift\Khd.Core.Thrift.csproj", "{205EBEBA-7AD4-4D1A-9282-052A74ED9C42}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Khd.Core.Thrift.Client", "src\Khd.Core.Thrift.Client\Khd.Core.Thrift.Client.csproj", "{2213CBB9-A843-4D73-AE3A-A26923E21855}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Khd.Core.Thrift.Server", "src\Khd.Core.Thrift.Server\Khd.Core.Thrift.Server.csproj", "{23371C02-98D7-4B01-80D6-542F6494D920}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Khd.Core.Wpf", "src\Khd.Core.Wpf\Khd.Core.Wpf.csproj", "{E28EBEAC-E51B-4905-97AD-0CE756E3E1EF}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {51C310CD-5D5C-49AF-A823-05743DFA84F9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {51C310CD-5D5C-49AF-A823-05743DFA84F9}.Debug|Any CPU.Build.0 = Debug|Any CPU + {51C310CD-5D5C-49AF-A823-05743DFA84F9}.Release|Any CPU.ActiveCfg = Release|Any CPU + {51C310CD-5D5C-49AF-A823-05743DFA84F9}.Release|Any CPU.Build.0 = Release|Any CPU + {44DF5518-A298-4B86-9169-6119ADF39B2D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {44DF5518-A298-4B86-9169-6119ADF39B2D}.Debug|Any CPU.Build.0 = Debug|Any CPU + {44DF5518-A298-4B86-9169-6119ADF39B2D}.Release|Any CPU.ActiveCfg = Release|Any CPU + {44DF5518-A298-4B86-9169-6119ADF39B2D}.Release|Any CPU.Build.0 = Release|Any CPU + {BAF46618-412D-4515-B4F5-D5F7BFE2ED7C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {BAF46618-412D-4515-B4F5-D5F7BFE2ED7C}.Debug|Any CPU.Build.0 = Debug|Any CPU + {BAF46618-412D-4515-B4F5-D5F7BFE2ED7C}.Release|Any CPU.ActiveCfg = Release|Any CPU + {BAF46618-412D-4515-B4F5-D5F7BFE2ED7C}.Release|Any CPU.Build.0 = Release|Any CPU + {CA8E36B3-560A-49AB-A51B-491879312E48}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {CA8E36B3-560A-49AB-A51B-491879312E48}.Debug|Any CPU.Build.0 = Debug|Any CPU + {CA8E36B3-560A-49AB-A51B-491879312E48}.Release|Any CPU.ActiveCfg = Release|Any CPU + {CA8E36B3-560A-49AB-A51B-491879312E48}.Release|Any CPU.Build.0 = Release|Any CPU + {B1981F15-21AD-4340-8818-36BB1AAA7E3D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {B1981F15-21AD-4340-8818-36BB1AAA7E3D}.Debug|Any CPU.Build.0 = Debug|Any CPU + {B1981F15-21AD-4340-8818-36BB1AAA7E3D}.Release|Any CPU.ActiveCfg = Release|Any CPU + {B1981F15-21AD-4340-8818-36BB1AAA7E3D}.Release|Any CPU.Build.0 = Release|Any CPU + {68C935C1-3FC2-42B2-A2CB-F1D4D3A8C507}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {68C935C1-3FC2-42B2-A2CB-F1D4D3A8C507}.Debug|Any CPU.Build.0 = Debug|Any CPU + {68C935C1-3FC2-42B2-A2CB-F1D4D3A8C507}.Release|Any CPU.ActiveCfg = Release|Any CPU + {68C935C1-3FC2-42B2-A2CB-F1D4D3A8C507}.Release|Any CPU.Build.0 = Release|Any CPU + {D924C4A2-85D6-46D1-86E0-CEBF66F897FD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {D924C4A2-85D6-46D1-86E0-CEBF66F897FD}.Debug|Any CPU.Build.0 = Debug|Any CPU + {D924C4A2-85D6-46D1-86E0-CEBF66F897FD}.Release|Any CPU.ActiveCfg = Release|Any CPU + {D924C4A2-85D6-46D1-86E0-CEBF66F897FD}.Release|Any CPU.Build.0 = Release|Any CPU + {205EBEBA-7AD4-4D1A-9282-052A74ED9C42}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {205EBEBA-7AD4-4D1A-9282-052A74ED9C42}.Debug|Any CPU.Build.0 = Debug|Any CPU + {205EBEBA-7AD4-4D1A-9282-052A74ED9C42}.Release|Any CPU.ActiveCfg = Release|Any CPU + {205EBEBA-7AD4-4D1A-9282-052A74ED9C42}.Release|Any CPU.Build.0 = Release|Any CPU + {2213CBB9-A843-4D73-AE3A-A26923E21855}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {2213CBB9-A843-4D73-AE3A-A26923E21855}.Debug|Any CPU.Build.0 = Debug|Any CPU + {2213CBB9-A843-4D73-AE3A-A26923E21855}.Release|Any CPU.ActiveCfg = Release|Any CPU + {2213CBB9-A843-4D73-AE3A-A26923E21855}.Release|Any CPU.Build.0 = Release|Any CPU + {23371C02-98D7-4B01-80D6-542F6494D920}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {23371C02-98D7-4B01-80D6-542F6494D920}.Debug|Any CPU.Build.0 = Debug|Any CPU + {23371C02-98D7-4B01-80D6-542F6494D920}.Release|Any CPU.ActiveCfg = Release|Any CPU + {23371C02-98D7-4B01-80D6-542F6494D920}.Release|Any CPU.Build.0 = Release|Any CPU + {E28EBEAC-E51B-4905-97AD-0CE756E3E1EF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {E28EBEAC-E51B-4905-97AD-0CE756E3E1EF}.Debug|Any CPU.Build.0 = Debug|Any CPU + {E28EBEAC-E51B-4905-97AD-0CE756E3E1EF}.Release|Any CPU.ActiveCfg = Release|Any CPU + {E28EBEAC-E51B-4905-97AD-0CE756E3E1EF}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {1938C827-EDD1-4789-AFB4-F08EC6DAA544} + EndGlobalSection +EndGlobal diff --git a/dll/HslCommunication.dll b/dll/HslCommunication.dll new file mode 100644 index 0000000..74af12f Binary files /dev/null and b/dll/HslCommunication.dll differ diff --git a/dll/S7.Net.dll b/dll/S7.Net.dll new file mode 100644 index 0000000..5be36c1 Binary files /dev/null and b/dll/S7.Net.dll differ diff --git a/dll/SevenZipSharp.dll b/dll/SevenZipSharp.dll new file mode 100644 index 0000000..1616630 Binary files /dev/null and b/dll/SevenZipSharp.dll differ diff --git a/src/Khd.Core.Api/.config/dotnet-tools.json b/src/Khd.Core.Api/.config/dotnet-tools.json new file mode 100644 index 0000000..337014b --- /dev/null +++ b/src/Khd.Core.Api/.config/dotnet-tools.json @@ -0,0 +1,12 @@ +{ + "version": 1, + "isRoot": true, + "tools": { + "dotnet-ef": { + "version": "5.0.10", + "commands": [ + "dotnet-ef" + ] + } + } +} \ No newline at end of file diff --git a/src/Khd.Core.Api/Controllers/RecieveRcsController.cs b/src/Khd.Core.Api/Controllers/RecieveRcsController.cs new file mode 100644 index 0000000..73a6a92 --- /dev/null +++ b/src/Khd.Core.Api/Controllers/RecieveRcsController.cs @@ -0,0 +1,145 @@ +using Khd.Core.Application.Interface; +using Khd.Core.Domain.Dto.webapi; +using Masuit.Tools; +using Masuit.Tools.Logging; +using Microsoft.AspNetCore.Mvc; +using System.IO; +using System.Threading; + +namespace Khd.Core.Api.Controllers +{ + [Route("wcs/[controller]")] + [ApiController] + public class RecieveRcsController : ControllerBase + { + private readonly IWcsTaskApplication _application; + + public RecieveRcsController(IWcsTaskApplication application) + { + _application = application; + } + + /// + /// 接收agv接收任务通知接口,三楼和五楼Agv接口 + /// + /// + /// + [HttpPost("agvCallback")] + public ReponseagvCallbackDto agvCallback(agvCallbackDto agvCallbackDto) + { + LogManager.Info($"RecieveRcsController接口信息:{agvCallbackDto.ToJsonString()}"); + Thread.Sleep(500); + return _application.AgvCallback(agvCallbackDto); + + } + + /// + /// 接收agv接收任务通知接口,二楼Agv接口 + /// + /// + /// + [HttpPost("agvCallback2")] + public ReponseagvCallbackDto agvCallback2(agvCallbackDto agvCallbackDto) + { + LogManager.Info($"RecieveRcsController接口信息:{agvCallbackDto.ToJsonString()}"); + Thread.Sleep(500); + return _application.AgvCallback2(agvCallbackDto); + + } + + /// + /// 背负式Agv通知任务完成 + /// + /// + /// + [HttpPost("agvComplete")] + public AgvCompeletedResponse MesToAgvComplete(AgvCompeleted agvCompeletedRequest) + { + LogManager.Info($"agvComplete接口信息:{agvCompeletedRequest.ToJsonString()}"); + return _application.MesToAgvComplete(agvCompeletedRequest); + } + + /// + /// 原材料入口任务继续通知 + /// + /// + /// + [HttpPost("taskContinue")] + public AgvCompeletedResponse TaskContinue(TaskContinue taskContinue) + { + LogManager.Info($"TaskContinue 接口收到消息: {taskContinue.ToJsonString()}"); + return _application.TaskContinue(taskContinue); + } + + /// + /// 通知去翻转机的任务 + /// + /// + /// + [HttpPost("callMaterial")] + public ReponseMessage CallMaterial(CallMaterial callMaterial) + { + LogManager.Info($"CallMaterial 接口收到消息: {callMaterial.ToJsonString()}"); + return _application.CallMaterial(callMaterial); + } + + [HttpPost("AgvTaskComplete")] + public ReponseMessage AGVTaskComplete() + { + LogManager.Info($"AgvTaskComplete 接口收到消息"); + return _application.AGVTaskComplete(); + } + + /// + /// 通知agv停止或启动 + /// + /// + /// + [HttpPost("AgvStopOrStart")] + public ReponseMessage AGVStopOrStart(CallAgvStopOrStart agvStopOrStart) + { + LogManager.Info($"AGVStopOrStart 接口收到消息: {agvStopOrStart.ToJsonString()}"); + return _application.CallAgvStopOrStart(agvStopOrStart); + } + + /// + /// 取消CTU预调度接口,WPF界面使用 + /// + /// + [HttpPost("CancelPreScheduling")] + public ReponseMessage CancelPreScheduling() + { + LogManager.Info($"CancelPreScheduling 接口收到消息"); + return _application.CancelPreScheduling(); + } + + [HttpGet] + public IActionResult Get(string fileName) + { + string path = Directory.GetCurrentDirectory() + "\\download\\" + fileName; + if (System.IO.File.Exists(path)) + { + byte[] fileBytes = System.IO.File.ReadAllBytes(path); + return File(fileBytes, "application/octet-stream", fileName); + } + else + { + return NotFound(); + } + } + + [HttpGet("version")] + public string GetVersion() + { + string path = Directory.GetCurrentDirectory() + "\\download\\" + "version.txt"; + if (System.IO.File.Exists(path)) + { + return System.IO.File.ReadAllText(path); + } + else + { + return "0.0.0.0"; + } + } + } +} \ No newline at end of file diff --git a/src/Khd.Core.Api/Khd.Core.Api.csproj b/src/Khd.Core.Api/Khd.Core.Api.csproj new file mode 100644 index 0000000..4ddcc19 --- /dev/null +++ b/src/Khd.Core.Api/Khd.Core.Api.csproj @@ -0,0 +1,46 @@ + + + + net6.0 + 051ea637-792d-470a-ad9f-3d79eb0f6635 + + + + bin\Debug\Khd.Core.Api.xml + bin\Debug + NU1605 + 1701;1702;1591 + + + + bin\Release + bin\Release\Khd.Core.Api.xml + NU1605 + 1701;1702;1591 + + + + + + + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + + + + + + + ..\..\dll\S7.Net.dll + + + + \ No newline at end of file diff --git a/src/Khd.Core.Api/Program.cs b/src/Khd.Core.Api/Program.cs new file mode 100644 index 0000000..fd18fe7 --- /dev/null +++ b/src/Khd.Core.Api/Program.cs @@ -0,0 +1,69 @@ +using Microsoft.AspNetCore.Hosting; +using Microsoft.Extensions.Hosting; +using System; +using System.IO; +using System.Linq; +using System.Timers; + +namespace Khd.Core.Api +{ + public class Program + { + public static void Main(string[] args) + { + #region ʱɾ־ + // öʱ24Сʱ86400000룩 + System.Timers.Timer timer = new System.Timers.Timer(86400000); + + timer.Elapsed += TimerElapsed; + timer.AutoReset = true; + timer.Start(); + + // ִɾ + DeleteOldLogFiles(); + #endregion + CreateHostBuilder(args).Build().Run(); + } + + private static void TimerElapsed(object sender, ElapsedEventArgs e) + { + DeleteOldLogFiles(); + } + + public static IHostBuilder CreateHostBuilder(string[] args) + { + return Host.CreateDefaultBuilder(args) + .ConfigureWebHostDefaults(webBuilder => + { + webBuilder.UseUrls("http://0.0.0.0:5001"); + webBuilder.UseStartup(); + }); + } + private static void DeleteOldLogFiles() + { + string logDirectory = AppDomain.CurrentDomain.BaseDirectory + "logs"; // 滻Ϊʵʵ־ļ· + DateTime cutoffDate = DateTime.Now.AddDays(-3); // 3ǰ + + try + { + DirectoryInfo dirInfo = new DirectoryInfo(logDirectory); + + // ȡ־ļɸѡҪɾļ + FileInfo[] logFiles = dirInfo.GetFiles("*.log") + .Where(file => file.LastWriteTime < cutoffDate) + .ToArray(); + + foreach (var file in logFiles) + { + // ɾļ + file.Delete(); + Console.WriteLine($"ɾļ{file.Name}"); + } + } + catch (Exception ex) + { + Console.WriteLine($"ɾ־ļʱִ{ex.Message}"); + } + } + } +} \ No newline at end of file diff --git a/src/Khd.Core.Api/Properties/launchSettings.json b/src/Khd.Core.Api/Properties/launchSettings.json new file mode 100644 index 0000000..eb86b0d --- /dev/null +++ b/src/Khd.Core.Api/Properties/launchSettings.json @@ -0,0 +1,22 @@ + { + "iisSettings": { + "windowsAuthentication": false, + "anonymousAuthentication": true, + "iisExpress": { + "applicationUrl": "http://localhost:63413", + "sslPort": 0 + } + }, + "$schema": "http://json.schemastore.org/launchsettings.json", + "profiles": { + "demo": { + "commandName": "Project", + "launchBrowser": true, + "launchUrl": "swagger", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "demo" + }, + "applicationUrl": "http://localhost:5001" + } + } +} \ No newline at end of file diff --git a/src/Khd.Core.Api/Startup.cs b/src/Khd.Core.Api/Startup.cs new file mode 100644 index 0000000..4414b97 --- /dev/null +++ b/src/Khd.Core.Api/Startup.cs @@ -0,0 +1,89 @@ +using Khd.Core.Application; +using Khd.Core.Domain.Configs; +using Khd.Core.EntityFramework; +using Khd.Core.Library; +using Khd.Core.Library.Swagger; +using Microsoft.AspNetCore.Authentication.JwtBearer; +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Hosting; +using Microsoft.EntityFrameworkCore; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; +using Microsoft.IdentityModel.Tokens; +using System; +using System.Text; + + +namespace Khd.Core.Api +{ + public class Startup + { + public Startup(IConfiguration configuration) + { + Configuration = configuration; + } + + private IConfiguration Configuration { get; } + + // This method gets called by the runtime. Use this method to add services to the container. + public void ConfigureServices(IServiceCollection services) + { + //services.AddDbContextPool( + // options => { options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")); }, 20); + + services.AddDbContext(options => + options.UseMySql(Configuration.GetConnectionString("DefaultConnection"), new MySqlServerVersion(new Version(8, 0, 31)))); + + services.AddOptions(); + services.Configure(Configuration.GetSection("JwtSecurityOption")); + + services.AddAuthentication(option => + { + option.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme; + option.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme; + }).AddJwtBearer(option => + { + option.RequireHttpsMetadata = false; + option.SaveToken = true; + option.TokenValidationParameters = new TokenValidationParameters + { + ValidateIssuerSigningKey = true, + ValidateIssuer = true, + ValidateAudience = true, + IssuerSigningKey = new SymmetricSecurityKey( + Encoding.Unicode.GetBytes(Configuration.GetSection("JwtSecurityOption:SigningKey").Value)), + ValidIssuer = Configuration.GetSection("JwtSecurityOption:Issuer").Value, + ValidAudience = Configuration.GetSection("JwtSecurityOption:Audience").Value + }; + }); + + services.AddCors(options => options.AddPolicy("CorsPolicy", builder => + { + builder + .AllowAnyOrigin() + .AllowAnyHeader() + .WithMethods("GET", "POST", "PUT", "DELETE", "OPTIONS"); + })); + + services.AddApplication(); + services.AddLibrary(); + } + + // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. + public void Configure(IApplicationBuilder app, IWebHostEnvironment env) + { + if (env.IsDevelopment()) app.UseDeveloperExceptionPage(); + + app.UseRouting(); + app.UseCors("CorsPolicy"); + + app.UseAuthentication(); + app.UseAuthorization(); + + app.UseEndpoints(endpoints => { endpoints.MapControllers(); }); + + app.UseLibrarySwagger(); + } + } +} \ No newline at end of file diff --git a/src/Khd.Core.Api/appsettings.json b/src/Khd.Core.Api/appsettings.json new file mode 100644 index 0000000..344b949 --- /dev/null +++ b/src/Khd.Core.Api/appsettings.json @@ -0,0 +1,26 @@ +{ + //"Logging": { + // "LogLevel": { + // "Default": "Information", + // "Microsoft": "Warning", + // "Microsoft.Hosting.Lifetime": "Information" + // }, + // "AppSettings": { + // "SiteCode": "999" + // } + //}, + "AllowedHosts": "*", + "ConnectionStrings": { + "DefaultConnection": "server=172.16.12.100;port=3306;database=hwjy-cloud;uid=kehaida;pwd=khdrkjy2024...;charset='utf8';persistsecurityinfo=True;SslMode=None;Allow User Variables=True" + //"DefaultConnection": "server=175.27.215.92;port=3306;database=hwjy-cloud;uid=kehaida;pwd=khd2024;charset='utf8';persistsecurityinfo=True;SslMode=None;Allow User Variables=True", + //"DefaultConnection": "server=175.27.215.92;port=3306;database=hwjy-cloud;uid=kehaida;pwd=khd2024;charset='utf8';persistsecurityinfo=True;SslMode=None;Allow User Variables=True", + //"DefaultConnection": "server=localhost;port=3306;database=jyhb;uid=root;pwd=root;charset='utf8';persistsecurityinfo=True;SslMode=None;Allow User Variables=True" + }, + "JwtSecurityOption": { + "SigningKey": "3c41f60c-1d12-11ec-890d-00163e1b8678", + "Issuer": "Khd.filog.cn", + "Audience": "Khd.filog.cn" + }, + "FileUploadingPath": "C:\\web\\images", + "FileServerHost": "/images/" +} diff --git a/src/Khd.Core.Application/ApplicationExtensions.cs b/src/Khd.Core.Application/ApplicationExtensions.cs new file mode 100644 index 0000000..fd145b9 --- /dev/null +++ b/src/Khd.Core.Application/ApplicationExtensions.cs @@ -0,0 +1,13 @@ +using Khd.Core.Application.Interface; +using Microsoft.Extensions.DependencyInjection; + +namespace Khd.Core.Application +{ + public static class ApplicationExtensions + { + public static void AddApplication(this IServiceCollection services) + { + services.AddTransient(); + } + } +} \ No newline at end of file diff --git a/src/Khd.Core.Application/HttpHelper.cs b/src/Khd.Core.Application/HttpHelper.cs new file mode 100644 index 0000000..f79cf3e --- /dev/null +++ b/src/Khd.Core.Application/HttpHelper.cs @@ -0,0 +1,170 @@ +using System; +using System.Collections.Generic; +using System.Net.Http; +using System.Text; +using System.Threading.Tasks; + +namespace Khd.Core.Application +{ + public class HttpHelper + { + + public static string SendPostMessage(string ip, int port, string url, string message, string contentType = "application/Text") + { + string retsult = HttpPost("http://" + ip + ":" + port + "/" + url, message, contentType, 30, null); + return retsult; + } + + + public static string SendGetMessage(string ip, int port, string url) + { + string retsult = HttpGet("http://" + ip + ":" + port + "/" + url); + return retsult; + } + + /// + /// 发起POST同步请求 + /// + /// + /// + /// + /// application/xml、application/json、application/text、application/x-www-form-urlencoded + /// 填充消息头 + /// + public static string HttpPost(string url, string postData = null, string contentType = null, int timeOut = 30, Dictionary headers = null) + { + postData = postData ?? ""; + using (HttpClient client = new HttpClient()) + { + if (headers != null) + { + foreach (var header in headers) + client.DefaultRequestHeaders.Add(header.Key, header.Value); + } + using (HttpContent httpContent = new StringContent(postData, Encoding.UTF8)) + { + if (contentType != null) + httpContent.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue(contentType); + + HttpResponseMessage response = client.PostAsync(url, httpContent).Result; + return response.Content.ReadAsStringAsync().Result; + } + } + } + + + /// + /// 发起POST异步请求 + /// + /// + /// + /// application/xml、application/json、application/text、application/x-www-form-urlencoded + /// 填充消息头 + /// + public static async Task HttpPostAsync(string url, string postData = null, string contentType = null, int timeOut = 30, Dictionary headers = null) + { + postData = postData ?? ""; + using (HttpClient client = new HttpClient()) + { + client.Timeout = new TimeSpan(0, 0, timeOut); + if (headers != null) + { + foreach (var header in headers) + client.DefaultRequestHeaders.Add(header.Key, header.Value); + } + using (HttpContent httpContent = new StringContent(postData, Encoding.UTF8)) + { + if (contentType != null) + httpContent.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue(contentType); + + HttpResponseMessage response = await client.PostAsync(url, httpContent); + return await response.Content.ReadAsStringAsync(); + } + } + } + + /// + /// 发起GET同步请求 + /// + /// + /// + /// + /// + public static string HttpGet(string url, Dictionary headers = null) + { + using (HttpClient client = new HttpClient()) + { + if (headers != null) + { + foreach (var header in headers) + client.DefaultRequestHeaders.Add(header.Key, header.Value); + } + HttpResponseMessage response = client.GetAsync(url).Result; + return response.Content.ReadAsStringAsync().Result; + } + } + + /// + /// 发起GET异步请求 + /// + /// + /// + /// + /// + public static async Task HttpGetAsync(string url, Dictionary headers = null) + { + using (HttpClient client = new HttpClient()) + { + if (headers != null) + { + foreach (var header in headers) + client.DefaultRequestHeaders.Add(header.Key, header.Value); + } + HttpResponseMessage response = await client.GetAsync(url); + return await response.Content.ReadAsStringAsync(); + } + } + + /// + /// 发起GET同步请求 + /// + /// + /// + /// + /// + public static string HttpDelete(string url, Dictionary headers = null) + { + using (HttpClient client = new HttpClient()) + { + if (headers != null) + { + foreach (var header in headers) + client.DefaultRequestHeaders.Add(header.Key, header.Value); + } + HttpResponseMessage response = client.DeleteAsync(url).Result; + return response.Content.ReadAsStringAsync().Result; + } + } + + /// + /// 发起GET异步请求 + /// + /// + /// + /// + /// + public static async Task HttpDeleteAsync(string url, Dictionary headers = null) + { + using (HttpClient client = new HttpClient()) + { + if (headers != null) + { + foreach (var header in headers) + client.DefaultRequestHeaders.Add(header.Key, header.Value); + } + HttpResponseMessage response = await client.DeleteAsync(url); + return await response.Content.ReadAsStringAsync(); + } + } + } +} diff --git a/src/Khd.Core.Application/Interface/IBaseApplication.cs b/src/Khd.Core.Application/Interface/IBaseApplication.cs new file mode 100644 index 0000000..c1fd0a0 --- /dev/null +++ b/src/Khd.Core.Application/Interface/IBaseApplication.cs @@ -0,0 +1,9 @@ +namespace Khd.Core.Application.Interface +{ + public interface IBaseApplication + { + + } + + +} \ No newline at end of file diff --git a/src/Khd.Core.Application/Interface/IWcsTaskApplication.cs b/src/Khd.Core.Application/Interface/IWcsTaskApplication.cs new file mode 100644 index 0000000..0eb8045 --- /dev/null +++ b/src/Khd.Core.Application/Interface/IWcsTaskApplication.cs @@ -0,0 +1,40 @@ +using Khd.Core.Domain.Dto.webapi; +using Khd.Core.Domain.Models; + +namespace Khd.Core.Application.Interface +{ + public interface IWcsTaskApplication : IBaseApplication + { + WcsTask Get(int id); + WcsTask Add(WcsTask model); + WcsTask Update(WcsTask model); + + ReponseagvCallbackDto AgvCallback(agvCallbackDto agvCallbackDto); + + /// + /// 入库完成 + /// + /// + string InWare(long taskId); + /// + /// 出库完成 + /// + /// + string OutWare(long taskId); + + + AgvCompeletedResponse MesToAgvComplete(AgvCompeleted agvCompeletedRequest); + + + AgvCompeletedResponse TaskContinue(TaskContinue taskContinue); + + AgvCompeletedResponse TaskReturn(TaskReturn taskReturn); + ReponseagvCallbackDto AgvCallback2(agvCallbackDto agvCallbackDto); + ReponseMessage CallMaterial(CallMaterial callMaterial); + ReponseMessage AGVTaskComplete(); + ReponseMessage CallAgvStopOrStart(CallAgvStopOrStart agvStopOrStart); + + + ReponseMessage CancelPreScheduling(); + } +} \ No newline at end of file diff --git a/src/Khd.Core.Application/Khd.Core.Application.csproj b/src/Khd.Core.Application/Khd.Core.Application.csproj new file mode 100644 index 0000000..103eb07 --- /dev/null +++ b/src/Khd.Core.Application/Khd.Core.Application.csproj @@ -0,0 +1,26 @@ + + + + net6.0 + + + + + + + + + + + + + + + + + + ..\..\dll\S7.Net.dll + + + + \ No newline at end of file diff --git a/src/Khd.Core.Application/WcsTaskApplication.cs b/src/Khd.Core.Application/WcsTaskApplication.cs new file mode 100644 index 0000000..db2fca2 --- /dev/null +++ b/src/Khd.Core.Application/WcsTaskApplication.cs @@ -0,0 +1,527 @@ +using Jc.SnowId; +using Khd.Core.Application.Interface; +using Khd.Core.Domain.Dto.webapi; +using Khd.Core.Domain.Models; +using Khd.Core.EntityFramework; +using Masuit.Tools; +using Masuit.Tools.Logging; +using Microsoft.EntityFrameworkCore; +using Microsoft.Extensions.DependencyInjection; +using Newtonsoft.Json; +using System; +using System.Linq; +using Z.EntityFramework.Plus; + +namespace Khd.Core.Application +{ + public class WcsTaskApplication : IWcsTaskApplication + { + private readonly DefaultDbContext _dbContext; + private readonly static JcSnowId _snowId = new JcSnowId(); + + public WcsTaskApplication(IServiceProvider serviceProvider) + { + _dbContext = serviceProvider.GetService(); + } + + public WcsTask Get(int id) + { + var entity = _dbContext.WcsTask + .Where(c => 1 == 1) + .FirstOrDefault(); + return entity; + } + + public WcsTask Add(WcsTask model) + { + var entity = _dbContext.Add(model); + _dbContext.SaveChanges(); + return entity.Entity; + + } + + public WcsTask Update(WcsTask model) + { + var list = _dbContext.WcsTask.Where(t => t.objid == model.objid).Update(a => model); + return model; + } + + /// + /// 接收agv接收任务通知接口 + /// + /// + /// + public ReponseagvCallbackDto AgvCallback(agvCallbackDto agvCallbackDto) + { + ReponseagvCallbackDto reponseagvCallbackDto = new ReponseagvCallbackDto(); + try + { + _dbContext.ChangeTracker.Clear(); + WcsTask wcsTask = _dbContext.WcsTask.FirstOrDefault(t => t.taskCode == agvCallbackDto.taskCode); + if (wcsTask != null) + { + //start 开始 end结束 continue继续 + //待取货 + if (agvCallbackDto.method.ToLower() == "start") + { + wcsTask.taskStatus = 2; + _dbContext.Update(wcsTask); + _dbContext.WcsTaskLog.Where(t => t.objid == wcsTask.objid).Update(t => new WcsTaskLog { taskStatus = 2 }); + _dbContext.SaveChanges(); + reponseagvCallbackDto.code = "0"; + reponseagvCallbackDto.message = "成功"; + } + if (agvCallbackDto.method.ToLower() == "con") + { + wcsTask.taskStatus = 4; + _dbContext.Update(wcsTask); + _dbContext.WcsTaskLog.Where(t => t.objid == wcsTask.objid).Update(t => new WcsTaskLog { taskStatus = 4 }); + _dbContext.SaveChanges(); + reponseagvCallbackDto.code = "0"; + reponseagvCallbackDto.message = "成功"; + } + //已取货待放货 + if (agvCallbackDto.method.ToLower() == "continue") + { + + wcsTask.taskStatus = 3; + _dbContext.Update(wcsTask); + _dbContext.WcsTaskLog.Where(t => t.objid == wcsTask.objid).Update(t => new WcsTaskLog { taskStatus = 3 }); + _dbContext.SaveChanges(); + reponseagvCallbackDto.code = "0"; + reponseagvCallbackDto.message = "成功"; + } + //放货完成 + if (agvCallbackDto.method.ToLower() == "end") + { + if (wcsTask.nextPointId != 10) + { + wcsTask.taskStatus = 5; + + _dbContext.Update(wcsTask); + _dbContext.WcsTaskLog.Where(t => t.objid == wcsTask.objid).Update(t => new WcsTaskLog { taskStatus = 5 }); + _dbContext.SaveChanges(); + reponseagvCallbackDto.code = "0"; + reponseagvCallbackDto.message = "成功"; + } + else + { + wcsTask.taskStatus = 6; + _dbContext.Update(wcsTask); + _dbContext.WcsTaskLog.Where(t => t.objid == wcsTask.objid).Update(t => new WcsTaskLog { taskStatus = 6 }); + _dbContext.SaveChanges(); + reponseagvCallbackDto.code = "0"; + reponseagvCallbackDto.message = "成功"; + } + } + } + else + { + reponseagvCallbackDto.code = "1"; + reponseagvCallbackDto.message = "未找到当前任务"; + } + } + catch (Exception ex) + { + LogManager.Error(ex); + reponseagvCallbackDto.code = "1"; + reponseagvCallbackDto.message = ex.Message; + } + //返回请求 + reponseagvCallbackDto.reqCode = reponseagvCallbackDto.reqCode; + return reponseagvCallbackDto; + + } + + /// + /// 入库完成 + /// + /// + public string InWare(long taskId) + { + return ""; + } + + /// + /// 出库完成 + /// + /// + public string OutWare(long taskId) + { + return ""; + } + + /// + /// 背负式Agv通知完成 + /// + /// + /// + public AgvCompeletedResponse MesToAgvComplete(AgvCompeleted agvCompeletedRequest) + { + AgvCompeletedResponse agvCompeletedResponse = new AgvCompeletedResponse(); + try + { + _dbContext.ChangeTracker.Clear(); + BaseEquip baseEquip = _dbContext.BaseEquip.FirstOrDefault(t => t.equipNo == agvCompeletedRequest.endStationCode); + if (baseEquip != null) + { + var wcsTask = _dbContext.WcsTask + .Where(t => (t.taskType == 32 || t.taskType == 48) && (t.endPointId == baseEquip.objid || t.currPointId == baseEquip.objid)) + .OrderBy(t => t.createTime) + .FirstOrDefault(); + if (wcsTask != null) + { + LogManager.Info($"agvComplete接口找到任务:{wcsTask.ToJsonString()}"); + if (wcsTask.taskType != 48 && wcsTask.taskStatus != 0) + { + wcsTask.taskStatus = 7; + _dbContext.Update(wcsTask); + _dbContext.WcsTaskLog.Where(t => t.objid == wcsTask.objid).Update(t => new WcsTaskLog { taskStatus = 7 }); + _dbContext.SaveChanges(); + agvCompeletedResponse.code = "0"; + agvCompeletedResponse.message = "成功"; + LogManager.Info($"agvComplete更新任务状态7{wcsTask.ToJsonString()}"); + } + else if (wcsTask.taskStatus != 0) + { + wcsTask.taskStatus = 4; + _dbContext.Update(wcsTask); + _dbContext.WcsTaskLog.Where(t => t.objid == wcsTask.objid).Update(t => new WcsTaskLog { taskStatus = 7 }); + _dbContext.SaveChanges(); + agvCompeletedResponse.code = "0"; + agvCompeletedResponse.message = "成功"; + } + else + { + agvCompeletedResponse.code = "1"; + agvCompeletedResponse.message = "未找到当前任务"; + } + } + else + { + agvCompeletedResponse.code = "1"; + agvCompeletedResponse.message = "未找到当前任务"; + } + } + else + { + agvCompeletedResponse.code = "1"; + agvCompeletedResponse.message = "未找到当前工位"; + } + } + catch (Exception ex) + { + LogManager.Error(ex); + agvCompeletedResponse.code = "1"; + agvCompeletedResponse.message = ex.Message; + } + return agvCompeletedResponse; + } + + /// + /// 4楼到5楼原材料入口继续 + /// + /// + /// + public AgvCompeletedResponse TaskContinue(TaskContinue taskContinue) + { + AgvCompeletedResponse compeletedResponse = new AgvCompeletedResponse(); + try + { + _dbContext.ChangeTracker.Clear(); + var wcsTask = _dbContext.WcsTask + .Where(t => t.taskType == 47) + .Where(t => t.containerNo == taskContinue.palletInfoCode) + .FirstOrDefault(); + if (wcsTask != null) + { + wcsTask.useFlag = 1; + _dbContext.Update(wcsTask); + _dbContext.WcsTaskLog.Where(t => t.objid == wcsTask.objid).Update(a => new WcsTaskLog { useFlag = 1 }); + _dbContext.SaveChanges(); + compeletedResponse.code = "0"; + compeletedResponse.message = "成功"; + } + else + { + compeletedResponse.code = "1"; + compeletedResponse.message = "未找到当前任务"; + } + } + catch (Exception ex) + { + LogManager.Error(ex); + compeletedResponse.code = "1"; + compeletedResponse.message = ex.Message; + } + return compeletedResponse; + } + + /// + /// 柜体拆分区通知返库 + /// + /// + /// + public AgvCompeletedResponse TaskReturn(TaskReturn taskReturn) + { + AgvCompeletedResponse compeletedResponse = new AgvCompeletedResponse(); + try + { + _dbContext.ChangeTracker.Clear(); + WcsTask wcsTask = _dbContext.WcsTask + .Where(t => t.taskType == 28) + .Where(t => t.endPointNo == taskReturn.endStationCode) + .FirstOrDefault(); + if (wcsTask != null) + { + wcsTask.useFlag = 1; + _dbContext.Update(wcsTask); + _dbContext.WcsTask.Where(t => t.objid == wcsTask.objid).Update(a => new WcsTask { useFlag = 1 }); + _dbContext.SaveChanges(); + compeletedResponse.code = "0"; + compeletedResponse.message = "成功"; + } + else + { + compeletedResponse.code = "1"; + compeletedResponse.message = "未找到当前任务"; + } + } + catch (Exception ex) + { + LogManager.Error(ex); + compeletedResponse.code = "1"; + compeletedResponse.message = ex.Message; + } + return compeletedResponse; + } + + public ReponseagvCallbackDto AgvCallback2(agvCallbackDto agvCallbackDto) + { + ReponseagvCallbackDto reponseagvCallbackDto = new ReponseagvCallbackDto(); + try + { + _dbContext.ChangeTracker.Clear(); + WcsTask wcsTask = _dbContext.WcsTask.FirstOrDefault(t => t.taskCode == agvCallbackDto.taskCode); + if (wcsTask != null) + { + //start 开始 end结束 continue继续 + //待取货 + if (agvCallbackDto.method.ToLower() == "start") + { + wcsTask.taskStatus = 2; + _dbContext.Update(wcsTask); + _dbContext.WcsTaskLog.Where(t => t.objid == wcsTask.objid).Update(t => new WcsTaskLog { taskStatus = 2 }); + _dbContext.SaveChanges(); + reponseagvCallbackDto.code = "0"; + reponseagvCallbackDto.message = "成功"; + } + if (agvCallbackDto.method.ToLower() == "con") + { + wcsTask.taskStatus = 4; + _dbContext.Update(wcsTask); + _dbContext.WcsTaskLog.Where(t => t.objid == wcsTask.objid).Update(t => new WcsTaskLog { taskStatus = 4 }); + _dbContext.SaveChanges(); + reponseagvCallbackDto.code = "0"; + reponseagvCallbackDto.message = "成功"; + } + //已取货待放货 + if (agvCallbackDto.method.ToLower() == "continue") + { + if (wcsTask.taskStatus > 3) + { + wcsTask.taskStatus = 5; + _dbContext.Update(wcsTask); + _dbContext.WcsTaskLog.Where(t => t.objid == wcsTask.objid).Update(t => new WcsTaskLog { taskStatus = 5 }); + _dbContext.SaveChanges(); + reponseagvCallbackDto.code = "0"; + reponseagvCallbackDto.message = "成功"; + } + else + { + wcsTask.taskStatus = 3; + _dbContext.Update(wcsTask); + _dbContext.WcsTaskLog.Where(t => t.objid == wcsTask.objid).Update(t => new WcsTaskLog { taskStatus = 3 }); + _dbContext.SaveChanges(); + reponseagvCallbackDto.code = "0"; + reponseagvCallbackDto.message = "成功"; + } + } + //放货完成 + if (agvCallbackDto.method.ToLower() == "end") + { + wcsTask.taskStatus = 7; + _dbContext.Update(wcsTask); + _dbContext.WcsTaskLog.Where(t => t.objid == wcsTask.objid).Update(t => new WcsTaskLog { taskStatus = 7 }); + _dbContext.SaveChanges(); + reponseagvCallbackDto.code = "0"; + reponseagvCallbackDto.message = "成功"; + } + } + + } + catch (Exception ex) + { + LogManager.Error(ex); + reponseagvCallbackDto.code = "1"; + reponseagvCallbackDto.message = ex.Message; + } + //返回请求 + reponseagvCallbackDto.reqCode = reponseagvCallbackDto.reqCode; + return reponseagvCallbackDto; + } + + public ReponseMessage CallMaterial(CallMaterial callMaterial) + { + ReponseMessage reponseMessage = new ReponseMessage(); + try + { + _dbContext.ChangeTracker.Clear(); + // WmsRawOutstock wmsRawOutstock = _dbContext.WmsRawOutstock.FirstOrDefault(t => t.rawOutstockId == Convert.ToInt64(callMaterial.rawOutstockId)); + //if (wmsRawOutstock != null) + //{ + bool hasTask = _dbContext.WcsTask.Where(t => t.currPointId == 31 || t.endPointId == 31).Any(); + var taskManual = _dbContext.WcsTaskManual.Where(t => t.taskType == 999).FirstOrDefault(); + if (hasTask) + { + reponseMessage.code = "1"; + reponseMessage.message = "当前有任务,请等待任务完成后再申请"; + } + else + { + if(taskManual == null) + { + BaseEquip endEquip = _dbContext.BaseEquip.First(t => t.objid == 31); + BaseEquip baseEquip = _dbContext.BaseEquip.First(t => t.objid == 9); + WcsTaskManual wcsTaskManual = new WcsTaskManual(); + wcsTaskManual.taskType = 999; + wcsTaskManual.objid = _snowId.NextId(); + wcsTaskManual.startPointNo = callMaterial.locationCode; + wcsTaskManual.orderId = Convert.ToInt64(callMaterial.rawOutstockId); + _dbContext.Add(wcsTaskManual); + _dbContext.SaveChanges(); + reponseMessage.code = "0"; + reponseMessage.message = "成功"; + } + else + { + taskManual.startPointNo = callMaterial.locationCode; + taskManual.updateTime = DateTime.Now; + _dbContext.WcsTaskManual.Update(taskManual); + _dbContext.SaveChanges(); + reponseMessage.code = "0"; + reponseMessage.message = "修改成功"; + } + } + //} + //else + //{ + // reponseMessage.code = "1"; + // reponseMessage.message = "未找到当前申请单的任务"; + //} + } + catch (Exception ex) + { + reponseMessage.code = "1"; + reponseMessage.message = ex.Message; + LogManager.Error(ex); + } + return reponseMessage; + } + + public ReponseMessage AGVTaskComplete() + { + ReponseMessage reponseMessage = new ReponseMessage(); + try + { + _dbContext.ChangeTracker.Clear(); + bool hasTask = _dbContext.WcsTask.Where(t => t.taskType == 41).Any(); + if (!hasTask) + { + reponseMessage.code = "0"; + reponseMessage.message = "成功"; + } + else + { + reponseMessage.code = "1"; + reponseMessage.message = "当前不可翻转"; + } + } + catch (Exception ex) + { + reponseMessage.code = "1"; + reponseMessage.message = ex.Message; + LogManager.Error(ex); + } + return reponseMessage; + } + + public ReponseMessage CallAgvStopOrStart(CallAgvStopOrStart agvStopOrStart) + { + try + { + string Ip = "172.16.12.24"; + int Port = 8182; + if (agvStopOrStart.Meth.ToLower() == "stop") + { + var AgvMessage = new + { + reqCode = _snowId.NextId().ToString(), + robots = new string[] { agvStopOrStart.AgvCode } + }; + string result = HttpHelper.SendPostMessage(Ip, Port, "rcms/services/rest/hikRpcService/stopRobot", AgvMessage.ToJsonString()); + ReponseMessage reponseMessage = JsonConvert.DeserializeObject(result); + return reponseMessage; + } + else if (agvStopOrStart.Meth.ToLower() == "start") + { + var AgvMessage = new + { + reqCode = _snowId.NextId().ToString(), + robots = new string[] { agvStopOrStart.AgvCode } + }; + string result = HttpHelper.SendPostMessage(Ip, Port, "rcms/services/rest/hikRpcService/resumeRobot", AgvMessage.ToJsonString()); + ReponseMessage reponseMessage = JsonConvert.DeserializeObject(result); + return reponseMessage; + } + else + { + return new ReponseMessage() { code = "1", message = "传入Meth不正确" }; + } + } + catch + { + return new ReponseMessage() { code = "1", message = "调用失败" }; + } + } + + + /// + /// 取消预调度 + /// + /// + public ReponseMessage CancelPreScheduling() + { + try + { + _dbContext.ChangeTracker.Clear(); + var baseEquip = _dbContext.BaseEquip.FirstOrDefault(x => x.objid == 11); + var executeTask = new + { + reqCode = new JcSnowId().NextId().ToString(), + positionCode = "CTU_IN", + nextTask = -1 + }; + string executeMessage = JsonConvert.SerializeObject(executeTask); + string executeResult = HttpHelper.SendPostMessage(baseEquip.serverIp, baseEquip.serverPort.Value, "rcms/services/rest/hikRpcService/genPreScheduleTask", executeMessage); + ReponseMessage reponseMessage = JsonConvert.DeserializeObject(executeResult); + return reponseMessage; + + } + catch (Exception ex) + { + return new ReponseMessage() { code = "1", message = "调用失败" }; + } + } + } +} \ No newline at end of file diff --git a/src/Khd.Core.Domain/Auth/SysMenu.cs b/src/Khd.Core.Domain/Auth/SysMenu.cs new file mode 100644 index 0000000..ae3bf34 --- /dev/null +++ b/src/Khd.Core.Domain/Auth/SysMenu.cs @@ -0,0 +1,22 @@ +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; + +namespace Khd.Core.Domain.Auth +{ + [Table("wcs_sys_menu")] + public class SysMenu + { + [Key] + [Column("OBJID")] + public long? OBJID { get; set; } + + [Column("MENU_NAME")] + public string MenuName { get; set; } + + [Column("MENU_VISIBLE")] + public int MenuVisble { get; set; } + + [Column("MENU_ICON")] + public string MenuIcon { get; set; } + } +} diff --git a/src/Khd.Core.Domain/Auth/SysRole.cs b/src/Khd.Core.Domain/Auth/SysRole.cs new file mode 100644 index 0000000..6a7e794 --- /dev/null +++ b/src/Khd.Core.Domain/Auth/SysRole.cs @@ -0,0 +1,19 @@ +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; + +namespace Khd.Core.Domain.Auth +{ + [Table("wcs_sys_user_role")] + public class SysRole + { + [Key] + [Column("OBJID")] + public long? OBJID { get; set; } + + [Column("USER_ID")] + public long? UserId { get; set; } + + [Column("ROLE_ID")] + public long? RoleId { get; set; } + } +} diff --git a/src/Khd.Core.Domain/Auth/SysUser.cs b/src/Khd.Core.Domain/Auth/SysUser.cs new file mode 100644 index 0000000..d52b85d --- /dev/null +++ b/src/Khd.Core.Domain/Auth/SysUser.cs @@ -0,0 +1,32 @@ +using System; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; + +namespace Khd.Core.Domain.Auth +{ + [Table("wcs_sys_user")] + public class SysUser + { + [Key] + [Column("OBJID")] + public long? OBJID { get; set; } + + [Column("USER_NAME")] + public string UserName { get; set; } + + [Column("NICK_NAME")] + public string NickName { get; set; } + + [Column("STATUS")] + public int Status { get; set; } + + [Column("USER_PWD")] + public string Password { get; set; } + + [Column("create_by")] + public string createBy { get; set; } + + [Column("create_time")] + public DateTime? createTime { get; set; } + } +} diff --git a/src/Khd.Core.Domain/Configs/JwtSecurityOption.cs b/src/Khd.Core.Domain/Configs/JwtSecurityOption.cs new file mode 100644 index 0000000..70d90bf --- /dev/null +++ b/src/Khd.Core.Domain/Configs/JwtSecurityOption.cs @@ -0,0 +1,12 @@ +namespace Khd.Core.Domain.Configs +{ + public class JwtSecurityOption + { + // * SigningKey length >= 16 * + public string SigningKey { get; set; } + + public string Issuer { get; set; } + + public string Audience { get; set; } + } +} \ No newline at end of file diff --git a/src/Khd.Core.Domain/Dto/LocationPlcDto.cs b/src/Khd.Core.Domain/Dto/LocationPlcDto.cs new file mode 100644 index 0000000..6abc794 --- /dev/null +++ b/src/Khd.Core.Domain/Dto/LocationPlcDto.cs @@ -0,0 +1,18 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Khd.Core.Domain.Dto +{ + public class LocationPlcDto + { + public int Id { get; set; } + public string Station { get; set; } + public string Address { get; set; } + public string locRow { get; set; } + public string locColumn { get; set; } + public string layerNum { get; set; } + } +} diff --git a/src/Khd.Core.Domain/Dto/agv/WcsAgvStatus.cs b/src/Khd.Core.Domain/Dto/agv/WcsAgvStatus.cs new file mode 100644 index 0000000..3004e5f --- /dev/null +++ b/src/Khd.Core.Domain/Dto/agv/WcsAgvStatus.cs @@ -0,0 +1,73 @@ +using Newtonsoft.Json; +using System; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; + +namespace Khd.Core.Domain.Dto.agv +{ + [Table("wcs_agv_status")] + public class WcsAgvStatus + { + [Column("battery")] + public string Battery { get; set; } + [Column("exclType")] + public string ExclType { get; set; } + [Column("mapCode")] + public string MapCode { get; set; } + [Column("online")] + public string Online { get; set; } + [Column("path")] + public string? Path2 + { + get + { + if (path != null && path.Length > 0) + { + string json = JsonConvert.SerializeObject(path); + return json; + } + else + { + return ""; + } + } + set + { + if (value != null && value.Length > 0) + { + path = JsonConvert.DeserializeObject(value); + } + else + { + path = null; + } + } + } + public string[] path; + [Column("podCode")] + public string PodCode { get; set; } + [Column("podDir")] + public string PodDir { get; set; } + [Column("posX")] + public string PosX { get; set; } + [Column("posY")] + public string PosY { get; set; } + [Key] + [Column("robotCode")] + public string RobotCode { get; set; } + [Column("robotDir")] + public string RobotDir { get; set; } + [Column("robotIp")] + public string robotIp { get; set; } + [Column("speed")] + public string Speed { get; set; } + [Column("status")] + public string Status { get; set; } + [Column("agvName")] + public string AgvName { get; set; } + [Column("stop")] + public string Stop { get; set; } + [Column("timestamp")] + public DateTime? DateNow { get; set; } + } +} diff --git a/src/Khd.Core.Domain/Dto/taskType/StaticTaskType.cs b/src/Khd.Core.Domain/Dto/taskType/StaticTaskType.cs new file mode 100644 index 0000000..02d3368 --- /dev/null +++ b/src/Khd.Core.Domain/Dto/taskType/StaticTaskType.cs @@ -0,0 +1,189 @@ +namespace Khd.Core.Domain.Dto.TaskType +{ + /// + /// 任务类型 + /// + public static class StaticTaskType + { + /// + /// 五楼辅料配送到工位 + /// + public const int FiveBearAgv = 32; + /// + /// 五楼辅料退库 + /// + public const int FiveAccessoryReturn = 48; + /// + /// 二楼输送线到小包入口 + /// + public const int SecondLineToSmallPackage = 51; + /// + /// 二楼废料工位到周转位 + /// + public const int SecondWasteToTransit = 56; + /// + /// 二楼小包出口到库位 + /// + public const int SecondSmallPackageToStorage = 49; + /// + /// 二楼周转位到提升机 + /// + public const int SecondTransitToLift = 57; + /// + /// 二楼库位到提升机 + /// + public const int SecondStorageToLift = 50; + /// + /// 二楼移库 + /// + public const int SecondRemove = 55; + /// + /// 二楼提升机到废料工位 + /// + public const int SecondLiftToWaste = 53; + /// + /// 二楼周转位到废料工位 + /// + public const int SecondTransitToWaste = 54; + /// + /// 二楼提升机到周转位 + /// + public const int SecondLiftToTransit = 58; + /// + /// 二楼周转位到小包入口 + /// + public const int SecondTransitToSmallPackage = 59; + /// + /// 三楼移库 + /// + public const int ThirdRemove = 67; + /// + /// 三楼原材料入库 + /// + public const int ThirdRawIn = 39; + /// + /// 三楼原材料到翻转机 + /// + public const int ThirdRawToFlip = 41; + /// + /// 三楼周转区到托盘收集架 + /// + public const int ThirdTransitToBin = 40; + /// + /// 三楼翻转机到托盘收集架 + /// + public const int ThirdFlipToBin = 42; + /// + /// 三楼托盘收集架到周转区 + /// + public const int ThirdBinToTransit = 43; + /// + /// 三楼周转区到提升机 + /// + public const int ThirdTransitToLift = 44; + /// + /// 五楼原材料入库 + /// + public const int FiveRawIn = 47; + /// + /// 五楼原材料到拆分 + /// + public const int FiveRawToSplit = 46; + /// + /// 五楼原材料拆分返库 + /// + public const int FiveRawSplitReturn = 28; + /// + /// 五楼移库 + /// + public const int FiveRemove = 66; + /// + /// 五楼原材料到背板安装 + /// + public const int FiveRawToBack = 33; + /// + /// 五楼半成品入库 + /// + public const int FiveHalfIn = 34; + /// + /// 五楼成品出库库 + /// + public const int FiveProductOut = 38; + /// + /// 五楼辅料入库 + /// + public const int FiveAccessoryIn = 29; + /// + /// 五楼辅料出库 + /// + public const int FiveAccessoryOut = 30; + /// + /// 五楼辅料盘库 + /// + public const int FiveAccessoryStorage = 100; + /// + /// 三楼接驳位转运空托盘到二楼 + /// + public const int ThirdTransitToSecond = 101; + /// + /// 五楼辅料移库 + /// + public const int FiveAccessoryRemove = 102; + /// + /// 人工任务 + /// + public const int PersonTask = 99; + /// + /// 五楼原材料退库 + /// + public const int FiveStockReturnTask = 90; + /// + /// 三楼原材料退库 + /// + public const int ThirdStockReturnTask = 91; + /// + /// 获取任务名称 + /// + public static string GetTaskName(int taskType) + { + return taskType switch + { + FiveBearAgv => "五楼辅料配送到工位", + FiveAccessoryReturn => "五楼辅料退库", + SecondLineToSmallPackage => "二楼输送线到小包入口", + SecondWasteToTransit => "二楼废料工位到周转位", + SecondSmallPackageToStorage => "二楼小包出口到库位", + SecondTransitToLift => "二楼周转位到提升机", + SecondStorageToLift => "二楼库位到提升机", + SecondRemove => "二楼移库", + SecondLiftToWaste => "二楼提升机到废料工位", + SecondTransitToWaste => "二楼周转位到废料工位", + SecondLiftToTransit => "二楼提升机到周转位", + SecondTransitToSmallPackage => "二楼周转位到小包入口", + ThirdRemove => "三楼移库", + ThirdRawIn => "三楼原材料入库", + ThirdRawToFlip => "三楼原材料到翻转机", + ThirdTransitToBin => "三楼周转区到托盘收集架", + ThirdFlipToBin => "三楼翻转机到托盘收集架", + ThirdBinToTransit => "三楼托盘收集架到周转区", + ThirdTransitToLift => "三楼周转区到提升机", + FiveRawIn => "五楼原材料入库", + FiveRawToSplit => "五楼原材料到拆分", + FiveRawSplitReturn => "五楼原材料拆分返库", + FiveRemove => "五楼移库", + FiveRawToBack => "五楼原材料到背板安装", + FiveHalfIn => "五楼半成品入库", + FiveProductOut => "五楼成品出库库", + FiveAccessoryIn => "五楼辅料入库", + FiveAccessoryOut => "五楼辅料出库", + FiveAccessoryStorage => "五楼辅料盘库", + ThirdTransitToSecond => "三楼接驳位转运空托盘到二楼", + FiveAccessoryRemove => "五楼辅料移库", + PersonTask => "人工任务", + FiveStockReturnTask => "五楼原材料退库", + ThirdStockReturnTask => "三楼原材料退库", + _ => "未知任务类型", + }; + } + } +} diff --git a/src/Khd.Core.Domain/Dto/waring/WaringType.cs b/src/Khd.Core.Domain/Dto/waring/WaringType.cs new file mode 100644 index 0000000..dbe2941 --- /dev/null +++ b/src/Khd.Core.Domain/Dto/waring/WaringType.cs @@ -0,0 +1,36 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Khd.Core.Domain.Dto.waring +{ + public enum WaringType + { + 提升机Plc通讯异常 = 5001, + U型线Plc通讯异常, + 设备Plc通讯异常, + 一楼接驳位异常, + 二楼楼接驳位异常, + 三楼接驳位异常, + 四楼接驳位异常, + 五楼接驳位异常, + 五楼CTU入库任务创建失败, + 五楼CTU出库任务创建失败, + 五楼背负任务创建失败, + 五楼入库任务创建失败, + 五楼移库任务创建失败, + 五楼出库任务创建失败, + 二楼入库任务创建失败, + 二楼移库任务创建失败, + 二楼出库任务创建失败, + 三楼入库任务创建失败, + 三楼移库任务创建失败, + 三楼出库任务创建失败, + 绑定物料无仓库信息, + 提升机任务下发异常, + + } +} diff --git a/src/Khd.Core.Domain/Dto/wcs/NodeSetting.cs b/src/Khd.Core.Domain/Dto/wcs/NodeSetting.cs new file mode 100644 index 0000000..9ab0a83 --- /dev/null +++ b/src/Khd.Core.Domain/Dto/wcs/NodeSetting.cs @@ -0,0 +1,99 @@ +using System; + +namespace Khd.Core.Domain.Dto.wcs +{ + public class NodeSetting + { + public Guid id { get; set; } + + /// + /// 站台编码 + /// + + public string siteNo { get; set; } + + /// + /// 站台名称 + /// + + public string siteName { get; set; } + + /// + /// 站台类型 + /// + + public Guid? siteTasktype { get; set; } + + /// + /// ip地址 + /// + + public string siteIpaddress { get; set; } + + /// + /// 链接服务器端口号 + /// + + public int? siteServerport { get; set; } + + /// + /// thrift端口号 + /// + + public int? thriftPort { get; set; } + + + public int? isDelete { get; set; } + + /// + /// plc点位编码 + /// + + public string plcpointNo { get; set; } + + /// + /// plc点位编名称 + /// + + public string plcpointName { get; set; } + + /// + /// 点位长度 + /// + + public int? plcpointLength { get; set; } + + + public string plcpointAddress { get; set; } + + /// + /// 设备id + /// + + public Guid? plcpointEquipmentId { get; set; } + + /// + /// 设备编码 + /// + + public string plcpointEquipmentNo { get; set; } + + /// + /// 设备名称 + /// + + public string plcpointEquipmentName { get; set; } + + /// + /// plc点位数据类型 + /// + + public int? plcpointType { get; set; } + + /// + /// 站点id + /// + + public Guid? sitenodeId { get; set; } + } +} diff --git a/src/Khd.Core.Domain/Dto/wcs/PlcSetting.cs b/src/Khd.Core.Domain/Dto/wcs/PlcSetting.cs new file mode 100644 index 0000000..1f08165 --- /dev/null +++ b/src/Khd.Core.Domain/Dto/wcs/PlcSetting.cs @@ -0,0 +1,23 @@ +namespace Khd.Core.Domain.Dto.wcs +{ + public class PlcSetting + { + public string Id { get; set; } + /// + /// plc编码 + /// + public string PlcNo { get; set; } + /// + /// 地址位 + /// + public string PlcAddress { get; set; } + /// + /// 地址位长度 + /// + public string PlcValueLength { get; set; } + /// + /// 数据类型 + /// + public int PlcDataType { get; set; } + } +} diff --git a/src/Khd.Core.Domain/Dto/webapi/AgvCompeleted.cs b/src/Khd.Core.Domain/Dto/webapi/AgvCompeleted.cs new file mode 100644 index 0000000..ebc7c2c --- /dev/null +++ b/src/Khd.Core.Domain/Dto/webapi/AgvCompeleted.cs @@ -0,0 +1,32 @@ +namespace Khd.Core.Domain.Dto.webapi +{ + public class AgvCompeleted + { + public string stationId { get; set; } + public string endStationCode { get; set; } + public string stationState { get; set; } + public string method { get; set; } + } + + public class TaskContinue + { + public string BarCodeInfo { get; set; } + public string palletInfoCode { get; set; } + public long? materialId { get; set; } + public string endStationCode { get; set; } + } + + public class TaskReturn + { + public string BarCodeInfo { get; set; } + public string palletInfoCode { get; set; } + public long? materialId { get; set; } + public string endStationCode { get; set; } + } + + public class AgvCompeletedResponse + { + public string code { get; set; } + public string message { get; set; } + } +} diff --git a/src/Khd.Core.Domain/Dto/webapi/AgvStatusDto.cs b/src/Khd.Core.Domain/Dto/webapi/AgvStatusDto.cs new file mode 100644 index 0000000..8f3350a --- /dev/null +++ b/src/Khd.Core.Domain/Dto/webapi/AgvStatusDto.cs @@ -0,0 +1,31 @@ +using Khd.Core.Domain.Dto.agv; +using System.Collections.Generic; + +namespace Khd.Core.Domain.Dto.webapi +{ + public class AgvStatusDto + { + public string code { get; set; } + public List data { get; set; } + } + + public class cardStatus + { + public string battery { get; set; } + public string exclType { get; set; } + public string mapCode { get; set; } + public string online { get; set; } + public string[] path { get; set; } + public string podCode { get; set; } + public string podDir { get; set; } + public string posX { get; set; } + public string posY { get; set; } + public string robotCode { get; set; } + public string robotDir { get; set; } + public string robotIp { get; set; } + public string speed { get; set; } + public string status { get; set; } + public string stop { get; set; } + public string timestamp { get; set; } + } +} \ No newline at end of file diff --git a/src/Khd.Core.Domain/Dto/webapi/CallMaterial.cs b/src/Khd.Core.Domain/Dto/webapi/CallMaterial.cs new file mode 100644 index 0000000..58eac3a --- /dev/null +++ b/src/Khd.Core.Domain/Dto/webapi/CallMaterial.cs @@ -0,0 +1,15 @@ +namespace Khd.Core.Domain.Dto.webapi +{ + public class CallMaterial + { + public string rawOutstockId { get; set; } + public string locationCode { get; set; } + public string method { get; set; } + } + + public class CallAgvStopOrStart + { + public string Meth { get; set; } + public string AgvCode { get; set; } + } +} diff --git a/src/Khd.Core.Domain/Dto/webapi/ReponseBase.cs b/src/Khd.Core.Domain/Dto/webapi/ReponseBase.cs new file mode 100644 index 0000000..0a5c567 --- /dev/null +++ b/src/Khd.Core.Domain/Dto/webapi/ReponseBase.cs @@ -0,0 +1,55 @@ +using Khd.Core.Domain.Models; +using System.Collections.Generic; + +namespace Khd.Core.Domain.Dto.webapi +{ + public class RequestInfo + { + public List DATA { get; set; } + } + public class ReponseBase + { + public string CODE { get; set; } + public string MESSAGE { get; set; } + } + /// + /// 手工出库参数 + /// + public class ManualOutWareDto + { + public string MATERIAL_CODE { get; set; } + public string BATCH_NO { get; set; } + public int QTY { get; set; } + public string LOCALTION_CODE { get; set; } + public string ORDER_CODE { get; set; } + public string WARE_TYPE { get; set; } + public string CREATE_TIME { get; set; } + } + /// + /// 盘点参数 + /// + public class CheckDto + { + public string MATERIAL_CODE { get; set; } + public string BATCH_NO { get; set; } + public int QTY { get; set; } + public string LOCALTION_CODE { get; set; } + public string CHECK_CODE { get; set; } + + public string CREATE_TIME { get; set; } + } + /// + /// 手工出库入参 + /// + public class RequestManualOutWare + { + List DATA { get; set; } + } + /// + /// 盘点入参 + /// + public class RequestCheck + { + List DATA { get; set; } + } +} diff --git a/src/Khd.Core.Domain/Dto/webapi/agvCallback.cs b/src/Khd.Core.Domain/Dto/webapi/agvCallback.cs new file mode 100644 index 0000000..b7e5225 --- /dev/null +++ b/src/Khd.Core.Domain/Dto/webapi/agvCallback.cs @@ -0,0 +1,73 @@ +namespace Khd.Core.Domain.Dto.webapi +{ + //RCS调用WCS接口参数 + public class agvCallbackDto + { + /// + /// 请求编号,每个请求都要一个唯一编号, 同一个请求重复提交, 使用同一编号。; + /// + public string reqCode { get; set; } + /// + /// 请求时间截 格式: “yyyy-MM-dd HH:mm:ss”。 + /// + public string reqTime { get; set; } + public decimal cooX { get; set; } + public decimal cooY { get; set; } + public string currentPositionCode { get; set; } + public string data { get; set; } + public string mapCode { get; set; } + public string mapDataCode { get; set; } + public string stgBinCode { get; set; } + public string method { get; set; } + public string podCode { get; set; } + public string podDir { get; set; } + public string materialLot { get; set; } + public string materialType { get; set; } + public string robotCode { get; set; } + public string taskCode { get; set; } + public string wbCode { get; set; } + public string ctnrCode { get; set; } + public string ctnrType { get; set; } + public string roadWayCode { get; set; } + public string seq { get; set; } + public string eqpCode { get; set; } + + + + public string action { get; set; } + public string areaCode { get; set; } + public string berthCode { get; set; } + public string callCode { get; set; } + public string clientCode { get; set; } + public string currentCallCode { get; set; } + public string dstBinCode { get; set; } + public string indBind { get; set; } + public string layer { get; set; } + public string mapShortName { get; set; } + public string orgCode { get; set; } + public string podNum { get; set; } + public string podTyp { get; set; } + public string relatedArea { get; set; } + public string subTaskNum { get; set; } + public string tokenCode { get; set; } + public string username { get; set; } + public string whCode { get; set; } + } + public class ReponseagvCallbackDto + { + /// + /// 返回码 + /// + public string code { get; set; } + /// + /// 返回消息 + /// + public string message { get; set; } + /// + /// 请求编号 + /// + public string reqCode { get; set; } + + } + +} diff --git a/src/Khd.Core.Domain/Dto/webapi/continueTask.cs b/src/Khd.Core.Domain/Dto/webapi/continueTask.cs new file mode 100644 index 0000000..fe8fd5a --- /dev/null +++ b/src/Khd.Core.Domain/Dto/webapi/continueTask.cs @@ -0,0 +1,52 @@ +namespace Khd.Core.Domain.Dto.webapi +{ + //RCS调用WCS接口参数 + public class continueTaskDto + { + /// + /// 请求编号,每个请求都要一个唯一编号, 同一个请求重复提交, 使用同一编号。; + /// + public string reqCode { get; set; } + /// + /// 请求时间截 格式: “yyyy-MM-dd HH:mm:ss”。 + /// + public string reqTime { get; set; } + /// + /// 客户端编号,如PDA,HCWMS等。 + /// + public string clientCode { get; set; } + /// + /// 令牌号, 由调度系统颁发 + /// + public string tokenCode { get; set; } + /// + /// 工作位,与RCS-2000端配置的位置名称一致。 + /// + public string wbCode { get; set; } + /// + /// 货架号,采用货架号触发的方式。 + /// + public string podCode { get; set; } + public string agvCode { get; set; } + public string taskCode { get; set; } + public string taskSeq { get; set; } + public string nextPositionCode { get; set; } + } + public class ReponseagvcontinueTaskDto + { + /// + /// 返回码 + /// + public string code { get; set; } + /// + /// 返回消息 + /// + public string message { get; set; } + /// + /// 请求编号 + /// + public string reqCode { get; set; } + + } + +} diff --git a/src/Khd.Core.Domain/Dto/webapi/genAgvSchedulingTask.cs b/src/Khd.Core.Domain/Dto/webapi/genAgvSchedulingTask.cs new file mode 100644 index 0000000..af3021e --- /dev/null +++ b/src/Khd.Core.Domain/Dto/webapi/genAgvSchedulingTask.cs @@ -0,0 +1,145 @@ +using System.Collections.Generic; + +namespace Khd.Core.Domain.Dto.webapi +{ + //public class genAgvSchedulingTask + //{ + // public List DATA { get; set; } + //} + public class RequestAGVTaskDto + { + /// + /// 请求编号,每个请求都要一个唯一编号, 同一个请求重复提交, 使用同一编号。; + /// + public string reqCode { get; set; } + /// + /// 请求时间截 格式: “yyyy-MM-dd HH:mm:ss”。 + /// + public string reqTime { get; set; } + /// + /// 客户端编号,如PDA,HCWMS等。 + /// + public string clientCode { get; set; } + /// + /// 令牌号, 由调度系统颁发 + /// + public string tokenCode { get; set; } + /// + /// 任务类型, + /// 业务流程 + /// 5层柜体来料验收拆分 柜体物料 提升机输送线对接位-验收拆分区 WMS F501 2 + /// 5层柜体来料入库 柜体物料 验收拆分区-原材料周转区 WMS F502 2 + /// 5层辅料立体库物料入库 辅料料箱 回转输送线回库口-辅料库货架 WMS F503 1 + /// 5层辅料立体库分拣出库 辅料料箱 辅料库货架-回转输送线出库口 WMS F504 1 + /// 5层辅料立体库分拣回库 辅料料箱 回转输送线回库口-辅料库货架 WMS F505 1 + /// 5层辅料配送流程 辅料料箱 物料分拣位-装配区领料工位 WMS F506 空值 + /// 5层背板安装区物料配送 柜体物料 原材料周转区-背板安装区 WMS F507 2 + /// 5层半成品下线 半成品柜 背板安装区-半成品周转区 WMS F508 2 + /// 5层半成品检验 半成品柜 半成品周转区-检测台 WMS F509 2 + /// 5层成品柜体入库 成品柜体 检验台-成品区 WMS F510 2 + /// 5层成品柜体出库 成品柜体 成品区-提升机输送线对接点 WMS F511 2 + /// + public string taskTyp { get; set; } + /// + /// 容器类型(叉车/CTU专用)叉车项目必传 + /// + public string ctnrTyp { get; set; } + /// + /// 容器编号(叉车/CTU专用) + /// + public string ctnrCode { get; set; } + /// + /// 容器数量(叉车堆叠专用),默认值1,仅记录堆叠的数量不记录堆叠的每个容器号 + /// + public string ctnrNum { get; set; } + /// + /// 任务模式 0-普通move 1-出库move 2-入库move 3-移库move + /// + public string taskMode { get; set; } + /// + /// 工作位,一般为机台或工作台位置,与RCS-2000端配置的位置名称一致, 工作位名称为字母\数字\或组合, 不超过32位。 + /// + public string wbCode { get; set; } + /// + /// 位置路径:AGV关键路径位置集合,与任务类型中模板配置的位置路径一一对应。待现场地图部署、配置完成后可获取。 + /// + public List positionCodePath { get; set; } + /// + /// “180”,”0”,”90”,”-90” 分别对应地图的”左”,”右”,”上”,”下” ,不指定方向可以为空 + /// + public string podDir { get; set; } + /// + /// “180”,”0”,”90”,”-90” 分别对应地图的”左”,”右”,”上”,”下” ,不指定方向可以为空 + /// + public string podTyp { get; set; } + /// + /// “180”,”0”,”90”,”-90” 分别对应地图的”左”,”右”,”上”,”下” ,不指定方向可以为空 + /// + public string podCode { get; set; } + /// + /// 物料批次或货架上的物料唯一编码, + /// + public string materialLot { get; set; } + /// + /// 物料类型, 仅移载机器人协议专用必填, 其它车型任务不填 + /// + public string materialType { get; set; } + /// + /// 优先级,从(1~127)级,最大优先级最高。为空时,采用任务模板的优先级。 + /// + public string priority { get; set; } + /// + /// 任务单号,选填, 不填系统自动生成,UUID小于等于64位 + /// + public string taskCode { get; set; } + /// + /// AGV编号,填写表示指定某一编号的AGV执行该任务 + /// + public string agvCode { get; set; } + /// + /// 组编号 + /// + public string groupId { get; set; } + /// + /// 设备类型 + /// + public string agvTyp { get; set; } + /// + /// 区域/策略中挑选货架以及根据物料批次挑选货架时的先进先出规则 + /// + public string positionSelStrategy { get; set; } + public string data { get; set; } + } + public class Position + { + /// + /// 货架编号,不指定货架可以为空 + /// + public string positionCode { get; set; } + /// + /// 货架类型, 传空时表示随机找个货架 + /// + public string type { get; set; } + + } + + public class ReponseMessage + { + /// + /// 返回码 + /// + public string code { get; set; } + /// + /// 返回消息,成功或其他 + /// + public string message { get; set; } + /// + /// 请求编号 + /// + public string reqCode { get; set; } + /// + /// 自定义返回(返回任务单号) + /// + public string data { get; set; } + } +} diff --git a/src/Khd.Core.Domain/Khd.Core.Domain.csproj b/src/Khd.Core.Domain/Khd.Core.Domain.csproj new file mode 100644 index 0000000..1456594 --- /dev/null +++ b/src/Khd.Core.Domain/Khd.Core.Domain.csproj @@ -0,0 +1,23 @@ + + + + net6.0 + + + + Khd.Core.Api\bin\Debug\ + Khd.Core.Api\bin\Debug\Khd.Core.Domain.xml + 1701;1702;1591 + + + + Khd.Core.Api\bin\Release\ + Khd.Core.Api\bin\Release\Khd.Core.Domain.xml + 1701;1702;1591 + + + + + + + \ No newline at end of file diff --git a/src/Khd.Core.Domain/Models/BaseAlertinfo.cs b/src/Khd.Core.Domain/Models/BaseAlertinfo.cs new file mode 100644 index 0000000..5632be5 --- /dev/null +++ b/src/Khd.Core.Domain/Models/BaseAlertinfo.cs @@ -0,0 +1,89 @@ + +//----------------------------------------------------------------------- +// +// * Copyright (C) 2021 KEHAIDASOFT All Rights Reserved +// * version : 4.0.30319.42000 +// * author : khd by t4-2 +// +//----------------------------------------------------------------------- + +using System; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; + +namespace Khd.Core.Domain.Models +{ + + [Table("base_alertinfo")] + public class BaseAlertinfo + { + + [Key] + [Column("id")] + public Guid id { get; set; } + + /// + /// 报警编码 + /// + [Column("alert_no")] + public string alertNo { get; set; } + + /// + /// 报警内容 + /// + [Column("alert_desc")] + public string alertDesc { get; set; } + + /// + /// 最小值 + /// + [Column("alert_minval")] + public int? alertMinval { get; set; } + + /// + /// 最大值 + /// + [Column("alert_maxval")] + public int? alertMaxval { get; set; } + + /// + /// 等于值 + /// + [Column("alert_equipval")] + public int? alertEquipval { get; set; } + + [Column("isdelete")] + public int? isdelete { get; set; } + + [Column("create_time")] + public DateTime? createTime { get; set; } + + [Column("create_id")] + public Guid? createId { get; set; } + + [Column("create_by")] + public string createBy { get; set; } + + [Column("modify_time")] + public DateTime? modifyTime { get; set; } + + [Column("modify_id")] + public Guid? modifyId { get; set; } + + [Column("modify_by")] + public string modifyBy { get; set; } + + [Column("definefield3")] + public string definefield3 { get; set; } + + [Column("definefield1")] + public string definefield1 { get; set; } + + [Column("definefield2")] + public string definefield2 { get; set; } + + [Column("line_id")] + public Guid? lineId { get; set; } + } +} + diff --git a/src/Khd.Core.Domain/Models/BaseAmima.cs b/src/Khd.Core.Domain/Models/BaseAmima.cs new file mode 100644 index 0000000..718a57c --- /dev/null +++ b/src/Khd.Core.Domain/Models/BaseAmima.cs @@ -0,0 +1,37 @@ + +//----------------------------------------------------------------------- +// +// * Copyright (C) 2021 KEHAIDASOFT All Rights Reserved +// * version : 4.0.30319.42000 +// * author : khd by t4-2 +// +//----------------------------------------------------------------------- + +using System; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; + +namespace Khd.Core.Domain.Models +{ + + [Table("base_amima")] + public class BaseAmima + { + + [Key] + [Column("id")] + public Guid id { get; set; } + + [Column("name")] + public string name { get; set; } + + [Column("password")] + public string password { get; set; } + + [Column("create_time")] + public DateTime? createTime { get; set; } + [Column("direction")] + public int direction { get; set; } + } +} + diff --git a/src/Khd.Core.Domain/Models/BaseArea.cs b/src/Khd.Core.Domain/Models/BaseArea.cs new file mode 100644 index 0000000..595c00c --- /dev/null +++ b/src/Khd.Core.Domain/Models/BaseArea.cs @@ -0,0 +1,110 @@ + +//----------------------------------------------------------------------- +// +// * Copyright (C) 2021 KEHAIDASOFT All Rights Reserved +// * version : 4.0.30319.42000 +// * author : khd by t4-2 +// +//----------------------------------------------------------------------- + +using System; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; + +namespace Khd.Core.Domain.Models +{ + + [Table("base_area")] + public class BaseArea + { + + [Key] + [Column("id")] + public Guid id { get; set; } + + /// + /// 区域编码 + /// + [Column("area_no")] + public string areaNo { get; set; } + + /// + /// 区域名称 + /// + [Column("area_name")] + public string areaName { get; set; } + + /// + /// 区域类型(1库区,0路线) + /// + [Column("area_type_id")] + public int? areaTypeId { get; set; } + + /// + /// 最大存储数 + /// + [Column("max_size")] + public int? maxSize { get; set; } + + /// + /// 库位序号 + /// + [Column("area_order")] + public int? areaOrder { get; set; } + + /// + /// 库区1,2 + /// + [Column("ware_house")] + public int? wareHouse { get; set; } + + [Column("is_delete")] + public int? isDelete { get; set; } + + [Column("create_time")] + public DateTime? createTime { get; set; } + + [Column("create_id")] + public Guid? createId { get; set; } + + [Column("create_by")] + public string createBy { get; set; } + + [Column("modify_time")] + public DateTime? modifyTime { get; set; } + + [Column("modify_id")] + public Guid? modifyId { get; set; } + + [Column("modify_by")] + public string modifyBy { get; set; } + + [Column("definefield3")] + public string definefield3 { get; set; } + + [Column("definefield1")] + public string definefield1 { get; set; } + + [Column("definefield2")] + public string definefield2 { get; set; } + + [Column("definefield4")] + public string definefield4 { get; set; } + + [Column("definefield5")] + public string definefield5 { get; set; } + + [Column("definefield6")] + public string definefield6 { get; set; } + + [Column("definefield7")] + public string definefield7 { get; set; } + + [Column("definefield8")] + public string definefield8 { get; set; } + + [Column("definefield9")] + public string definefield9 { get; set; } + } +} + diff --git a/src/Khd.Core.Domain/Models/BaseAsaveerro.cs b/src/Khd.Core.Domain/Models/BaseAsaveerro.cs new file mode 100644 index 0000000..206793e --- /dev/null +++ b/src/Khd.Core.Domain/Models/BaseAsaveerro.cs @@ -0,0 +1,65 @@ + +//----------------------------------------------------------------------- +// +// * Copyright (C) 2021 KEHAIDASOFT All Rights Reserved +// * version : 4.0.30319.42000 +// * author : khd by t4-2 +// +//----------------------------------------------------------------------- + +using System; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; + +namespace Khd.Core.Domain.Models +{ + + [Table("base_asaveerro")] + public class BaseAsaveerro + { + + [Key] + [Column("id")] + public Guid id { get; set; } + + /// + /// 区域编码 + /// + [Column("area_no")] + public string areaNo { get; set; } + + /// + /// 区域名称 + /// + [Column("area_name")] + public string areaName { get; set; } + + /// + /// 当库区车辆数与plc读取的车辆数不一致时,记录读取plc + /// + [Column("status")] + public string status { get; set; } + + [Column("is_delete")] + public int? isDelete { get; set; } + + [Column("create_time")] + public DateTime? createTime { get; set; } + + [Column("create_id")] + public Guid? createId { get; set; } + + [Column("create_by")] + public string createBy { get; set; } + + [Column("modify_time")] + public DateTime? modifyTime { get; set; } + + [Column("modify_id")] + public Guid? modifyId { get; set; } + + [Column("modify_by")] + public string modifyBy { get; set; } + } +} + diff --git a/src/Khd.Core.Domain/Models/BaseAsaveerroBak.cs b/src/Khd.Core.Domain/Models/BaseAsaveerroBak.cs new file mode 100644 index 0000000..e6e5b5f --- /dev/null +++ b/src/Khd.Core.Domain/Models/BaseAsaveerroBak.cs @@ -0,0 +1,65 @@ + +//----------------------------------------------------------------------- +// +// * Copyright (C) 2021 KEHAIDASOFT All Rights Reserved +// * version : 4.0.30319.42000 +// * author : khd by t4-2 +// +//----------------------------------------------------------------------- + +using System; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; + +namespace Khd.Core.Domain.Models +{ + + [Table("base_asaveerro_bak")] + public class BaseAsaveerroBak + { + + [Key] + [Column("id")] + public Guid id { get; set; } + + /// + /// 区域编码 + /// + [Column("area_no")] + public string areaNo { get; set; } + + /// + /// 区域名称 + /// + [Column("area_name")] + public string areaName { get; set; } + + /// + /// 当库区车辆数与plc读取的车辆数不一致时,记录读取plc + /// + [Column("status")] + public string status { get; set; } + + [Column("is_delete")] + public int? isDelete { get; set; } + + [Column("create_time")] + public DateTime? createTime { get; set; } + + [Column("create_id")] + public Guid? createId { get; set; } + + [Column("create_by")] + public string createBy { get; set; } + + [Column("modify_time")] + public DateTime? modifyTime { get; set; } + + [Column("modify_id")] + public Guid? modifyId { get; set; } + + [Column("modify_by")] + public string modifyBy { get; set; } + } +} + diff --git a/src/Khd.Core.Domain/Models/BaseAsaveplcnumber.cs b/src/Khd.Core.Domain/Models/BaseAsaveplcnumber.cs new file mode 100644 index 0000000..901b038 --- /dev/null +++ b/src/Khd.Core.Domain/Models/BaseAsaveplcnumber.cs @@ -0,0 +1,71 @@ + +//----------------------------------------------------------------------- +// +// * Copyright (C) 2021 KEHAIDASOFT All Rights Reserved +// * version : 4.0.30319.42000 +// * author : khd by t4-2 +// +//----------------------------------------------------------------------- + +using System; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; + +namespace Khd.Core.Domain.Models +{ + + [Table("base_asaveplcnumber")] + public class BaseAsaveplcnumber + { + + [Key] + [Column("id")] + public Guid id { get; set; } + + /// + /// 区域编码 + /// + [Column("area_no")] + public string areaNo { get; set; } + + /// + /// 区域名称 + /// + [Column("area_name")] + public string areaName { get; set; } + + /// + /// 当库区车辆数与plc读取的车辆数不一致时,记录读取plc + /// + [Column("plc_number")] + public string plcNumber { get; set; } + + /// + /// 当库区车辆数与plc读取的车辆数不一致时,记录 + /// + [Column("kuqu_number")] + public string kuquNumber { get; set; } + + [Column("is_delete")] + public int? isDelete { get; set; } + + [Column("create_time")] + public DateTime? createTime { get; set; } + + [Column("create_id")] + public Guid? createId { get; set; } + + [Column("create_by")] + public string createBy { get; set; } + + [Column("modify_time")] + public DateTime? modifyTime { get; set; } + + [Column("modify_id")] + public Guid? modifyId { get; set; } + + [Column("modify_by")] + public string modifyBy { get; set; } + } +} + diff --git a/src/Khd.Core.Domain/Models/BaseAsaveplcnumberBak.cs b/src/Khd.Core.Domain/Models/BaseAsaveplcnumberBak.cs new file mode 100644 index 0000000..e0d264b --- /dev/null +++ b/src/Khd.Core.Domain/Models/BaseAsaveplcnumberBak.cs @@ -0,0 +1,71 @@ + +//----------------------------------------------------------------------- +// +// * Copyright (C) 2021 KEHAIDASOFT All Rights Reserved +// * version : 4.0.30319.42000 +// * author : khd by t4-2 +// +//----------------------------------------------------------------------- + +using System; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; + +namespace Khd.Core.Domain.Models +{ + + [Table("base_asaveplcnumber_bak")] + public class BaseAsaveplcnumberBak + { + + [Key] + [Column("id")] + public Guid id { get; set; } + + /// + /// 区域编码 + /// + [Column("area_no")] + public string areaNo { get; set; } + + /// + /// 区域名称 + /// + [Column("area_name")] + public string areaName { get; set; } + + /// + /// 当库区车辆数与plc读取的车辆数不一致时,记录读取plc + /// + [Column("plc_number")] + public string plcNumber { get; set; } + + /// + /// 当库区车辆数与plc读取的车辆数不一致时,记录 + /// + [Column("kuqu_number")] + public string kuquNumber { get; set; } + + [Column("is_delete")] + public int? isDelete { get; set; } + + [Column("create_time")] + public DateTime? createTime { get; set; } + + [Column("create_id")] + public Guid? createId { get; set; } + + [Column("create_by")] + public string createBy { get; set; } + + [Column("modify_time")] + public DateTime? modifyTime { get; set; } + + [Column("modify_id")] + public Guid? modifyId { get; set; } + + [Column("modify_by")] + public string modifyBy { get; set; } + } +} + diff --git a/src/Khd.Core.Domain/Models/BaseBomcomponent.cs b/src/Khd.Core.Domain/Models/BaseBomcomponent.cs new file mode 100644 index 0000000..8ef1ae3 --- /dev/null +++ b/src/Khd.Core.Domain/Models/BaseBomcomponent.cs @@ -0,0 +1,80 @@ + +//----------------------------------------------------------------------- +// +// * Copyright (C) 2021 KEHAIDASOFT All Rights Reserved +// * version : 4.0.30319.42000 +// * author : khd by t4-2 +// +//----------------------------------------------------------------------- + +using System; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; + +namespace Khd.Core.Domain.Models +{ + + [Table("base_bomcomponent")] + public class BaseBomcomponent + { + + [Key] + [Column("id")] + public Guid id { get; set; } + + /// + /// bom + /// + [Column("bom_id")] + public Guid? bomId { get; set; } + + /// + /// 子级物料编码 + /// + [Column("bomcompenent_no")] + public string bomcompenentNo { get; set; } + + /// + /// 子级物料名称 + /// + [Column("bomcompenent_nm")] + public string bomcompenentNm { get; set; } + + /// + /// 数量 + /// + [Column("material_amount")] + public int? materialAmount { get; set; } + + [Column("is_delete")] + public int? isDelete { get; set; } + + [Column("create_time")] + public DateTime? createTime { get; set; } + + [Column("create_id")] + public Guid? createId { get; set; } + + [Column("create_by")] + public string createBy { get; set; } + + [Column("modify_time")] + public DateTime? modifyTime { get; set; } + + [Column("modify_id")] + public Guid? modifyId { get; set; } + + [Column("modify_by")] + public string modifyBy { get; set; } + + [Column("definefield3")] + public string definefield3 { get; set; } + + [Column("definefield1")] + public string definefield1 { get; set; } + + [Column("definefield2")] + public string definefield2 { get; set; } + } +} + diff --git a/src/Khd.Core.Domain/Models/BaseCar.cs b/src/Khd.Core.Domain/Models/BaseCar.cs new file mode 100644 index 0000000..09c7ae2 --- /dev/null +++ b/src/Khd.Core.Domain/Models/BaseCar.cs @@ -0,0 +1,62 @@ + +//----------------------------------------------------------------------- +// +// * Copyright (C) 2021 KEHAIDASOFT All Rights Reserved +// * version : 4.0.30319.42000 +// * author : khd by t4-2 +// +//----------------------------------------------------------------------- + +using System; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; + +namespace Khd.Core.Domain.Models +{ + + [Table("base_car")] + public class BaseCar + { + + [Key] + [Column("id")] + public Guid? id { get; set; } + + [Column("car_no")] + public int? carNo { get; set; } + + [Column("car_name")] + public string carName { get; set; } + + [Column("is_delete")] + public int? isDelete { get; set; } + + [Column("create_time")] + public DateTime? createTime { get; set; } + + [Column("create_id")] + public Guid? createId { get; set; } + + [Column("create_by")] + public string createBy { get; set; } + + [Column("modify_time")] + public DateTime? modifyTime { get; set; } + + [Column("modify_id")] + public Guid? modifyId { get; set; } + + [Column("modify_by")] + public string modifyBy { get; set; } + + [Column("definefield3")] + public string definefield3 { get; set; } + + [Column("definefield1")] + public string definefield1 { get; set; } + + [Column("definefield2")] + public string definefield2 { get; set; } + } +} + diff --git a/src/Khd.Core.Domain/Models/BaseCararea.cs b/src/Khd.Core.Domain/Models/BaseCararea.cs new file mode 100644 index 0000000..d8e8a6d --- /dev/null +++ b/src/Khd.Core.Domain/Models/BaseCararea.cs @@ -0,0 +1,122 @@ + +//----------------------------------------------------------------------- +// +// * Copyright (C) 2021 KEHAIDASOFT All Rights Reserved +// * version : 4.0.30319.42000 +// * author : khd by t4-2 +// +//----------------------------------------------------------------------- + +using System; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; + +namespace Khd.Core.Domain.Models +{ + + [Table("base_cararea")] + public class BaseCararea + { + + [Key] + [Column("id")] + public Guid? id { get; set; } + + /// + /// 库区线id + /// + [Column("area_id")] + public Guid? areaId { get; set; } + + /// + /// 库区线编码 + /// + [Column("area_no")] + public string areaNo { get; set; } + + /// + /// 库区线名称 + /// + [Column("area_name")] + public string areaName { get; set; } + + /// + /// 小车id + /// + [Column("car_id")] + public Guid? carId { get; set; } + + /// + /// 小车编码 + /// + [Column("car_no")] + public string carNo { get; set; } + + /// + /// 小车名称 + /// + [Column("car_name")] + public string carName { get; set; } + + /// + /// 物料id + /// + [Column("materiel_id")] + public Guid? materielId { get; set; } + + /// + /// 物料编码 + /// + [Column("materiel_no")] + public string materielNo { get; set; } + + /// + /// 物料名称 + /// + [Column("materiel_name")] + public string materielName { get; set; } + + /// + /// 物料扫描数量 + /// + [Column("materiel_num")] + public int? materielNum { get; set; } + + /// + /// 小车状态0入库中1入库2出库3倒库4下件带料返库5空车入库 + /// + [Column("car_status")] + public int? carStatus { get; set; } + + [Column("is_delete")] + public int? isDelete { get; set; } + + [Column("create_time")] + public DateTime? createTime { get; set; } + + [Column("create_id")] + public Guid? createId { get; set; } + + [Column("create_by")] + public string createBy { get; set; } + + [Column("modify_time")] + public DateTime? modifyTime { get; set; } + + [Column("modify_id")] + public Guid? modifyId { get; set; } + + [Column("modify_by")] + public string modifyBy { get; set; } + + [Column("definefield3")] + public string definefield3 { get; set; } + + [Column("definefield1")] + public string definefield1 { get; set; } + + [Column("definefield2")] + public string definefield2 { get; set; } + } +} + diff --git a/src/Khd.Core.Domain/Models/BaseCarareaRejects.cs b/src/Khd.Core.Domain/Models/BaseCarareaRejects.cs new file mode 100644 index 0000000..763083d --- /dev/null +++ b/src/Khd.Core.Domain/Models/BaseCarareaRejects.cs @@ -0,0 +1,122 @@ + +//----------------------------------------------------------------------- +// +// * Copyright (C) 2021 KEHAIDASOFT All Rights Reserved +// * version : 4.0.30319.42000 +// * author : khd by t4-2 +// +//----------------------------------------------------------------------- + +using System; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; + +namespace Khd.Core.Domain.Models +{ + + [Table("base_cararea_rejects")] + public class BaseCarareaRejects + { + + [Key] + [Column("id")] + public Guid id { get; set; } + + /// + /// 库区线id + /// + [Column("area_id")] + public Guid? areaId { get; set; } + + /// + /// 库区线编码 + /// + [Column("area_no")] + public string areaNo { get; set; } + + /// + /// 库区线名称 + /// + [Column("area_name")] + public string areaName { get; set; } + + /// + /// 小车id + /// + [Column("car_id")] + public Guid? carId { get; set; } + + /// + /// 小车编码 + /// + [Column("car_no")] + public string carNo { get; set; } + + /// + /// 小车名称 + /// + [Column("car_name")] + public string carName { get; set; } + + /// + /// 物料id + /// + [Column("materiel_id")] + public Guid? materielId { get; set; } + + /// + /// 物料编码 + /// + [Column("materiel_no")] + public string materielNo { get; set; } + + /// + /// 物料名称 + /// + [Column("materiel_name")] + public string materielName { get; set; } + + /// + /// 物料扫描数量 + /// + [Column("materiel_num")] + public int? materielNum { get; set; } + + /// + /// 小车状态0入库中1入库2出库3倒库4下件带料返库5空车入库 + /// + [Column("car_status")] + public int? carStatus { get; set; } + + [Column("is_delete")] + public int? isDelete { get; set; } + + [Column("create_time")] + public DateTime? createTime { get; set; } + + [Column("create_id")] + public Guid? createId { get; set; } + + [Column("create_by")] + public string createBy { get; set; } + + [Column("modify_time")] + public DateTime? modifyTime { get; set; } + + [Column("modify_id")] + public Guid? modifyId { get; set; } + + [Column("modify_by")] + public string modifyBy { get; set; } + + [Column("definefield3")] + public string definefield3 { get; set; } + + [Column("definefield1")] + public string definefield1 { get; set; } + + [Column("definefield2")] + public string definefield2 { get; set; } + } +} + diff --git a/src/Khd.Core.Domain/Models/BaseCarareaoverdue.cs b/src/Khd.Core.Domain/Models/BaseCarareaoverdue.cs new file mode 100644 index 0000000..069fcd8 --- /dev/null +++ b/src/Khd.Core.Domain/Models/BaseCarareaoverdue.cs @@ -0,0 +1,122 @@ + +//----------------------------------------------------------------------- +// +// * Copyright (C) 2021 KEHAIDASOFT All Rights Reserved +// * version : 4.0.30319.42000 +// * author : khd by t4-2 +// +//----------------------------------------------------------------------- + +using System; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; + +namespace Khd.Core.Domain.Models +{ + + [Table("base_carareaoverdue")] + public class BaseCarareaoverdue + { + + [Key] + [Column("id")] + public Guid id { get; set; } + + /// + /// 库区线id + /// + [Column("area_id")] + public Guid? areaId { get; set; } + + /// + /// 库区线编码 + /// + [Column("area_no")] + public string areaNo { get; set; } + + /// + /// 库区线名称 + /// + [Column("area_name")] + public string areaName { get; set; } + + /// + /// 小车id + /// + [Column("car_id")] + public Guid? carId { get; set; } + + /// + /// 小车编码 + /// + [Column("car_no")] + public string carNo { get; set; } + + /// + /// 小车名称 + /// + [Column("car_name")] + public string carName { get; set; } + + /// + /// 物料id + /// + [Column("materiel_id")] + public Guid? materielId { get; set; } + + /// + /// 物料编码 + /// + [Column("materiel_no")] + public string materielNo { get; set; } + + /// + /// 物料名称 + /// + [Column("materiel_name")] + public string materielName { get; set; } + + /// + /// 物料扫描数量 + /// + [Column("materiel_num")] + public int? materielNum { get; set; } + + /// + /// 小车状态0入库中1入库2出库3倒库4下件带料返库5空车入库 + /// + [Column("car_status")] + public int? carStatus { get; set; } + + [Column("is_delete")] + public int? isDelete { get; set; } + + [Column("create_time")] + public DateTime? createTime { get; set; } + + [Column("create_id")] + public Guid? createId { get; set; } + + [Column("create_by")] + public string createBy { get; set; } + + [Column("modify_time")] + public DateTime? modifyTime { get; set; } + + [Column("modify_id")] + public Guid? modifyId { get; set; } + + [Column("modify_by")] + public string modifyBy { get; set; } + + [Column("definefield3")] + public string definefield3 { get; set; } + + [Column("definefield1")] + public string definefield1 { get; set; } + + [Column("definefield2")] + public string definefield2 { get; set; } + } +} + diff --git a/src/Khd.Core.Domain/Models/BaseCargocage.cs b/src/Khd.Core.Domain/Models/BaseCargocage.cs new file mode 100644 index 0000000..78070a3 --- /dev/null +++ b/src/Khd.Core.Domain/Models/BaseCargocage.cs @@ -0,0 +1,98 @@ + +//----------------------------------------------------------------------- +// +// * Copyright (C) 2021 KEHAIDASOFT All Rights Reserved +// * version : 4.0.30319.42000 +// * author : khd by t4-2 +// +//----------------------------------------------------------------------- + +using System; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; + +namespace Khd.Core.Domain.Models +{ + + [Table("base_cargocage")] + public class BaseCargocage + { + + [Key] + [Column("id")] + public Guid id { get; set; } + + /// + /// 货笼编码 + /// + [Column("cargocage_no")] + public string cargocageNo { get; set; } + + /// + /// 货笼名称 + /// + [Column("cargocage_name")] + public string cargocageName { get; set; } + + /// + /// RFID编码 + /// + [Column("cargocage_rfid_no")] + public string cargocageRfidNo { get; set; } + + /// + /// 负载成品码 + /// + [Column("cargocage_materialno")] + public string cargocageMaterialno { get; set; } + + /// + /// 颜色 + /// + [Column("cargocage_color")] + public string cargocageColor { get; set; } + + /// + /// 当前状态 + /// + [Column("cargocage_status")] + public int? cargocageStatus { get; set; } + + /// + /// 操作时间 + /// + [Column("cargocage_optdate")] + public DateTime? cargocageOptdate { get; set; } + + [Column("is_delete")] + public int? isDelete { get; set; } + + [Column("create_time")] + public DateTime? createTime { get; set; } + + [Column("create_id")] + public Guid? createId { get; set; } + + [Column("create_by")] + public string createBy { get; set; } + + [Column("modify_time")] + public DateTime? modifyTime { get; set; } + + [Column("modify_id")] + public Guid? modifyId { get; set; } + + [Column("modify_by")] + public string modifyBy { get; set; } + + [Column("definefield3")] + public string definefield3 { get; set; } + + [Column("definefield1")] + public string definefield1 { get; set; } + + [Column("definefield2")] + public string definefield2 { get; set; } + } +} + diff --git a/src/Khd.Core.Domain/Models/BaseCarmateriel.cs b/src/Khd.Core.Domain/Models/BaseCarmateriel.cs new file mode 100644 index 0000000..c1ad08e --- /dev/null +++ b/src/Khd.Core.Domain/Models/BaseCarmateriel.cs @@ -0,0 +1,80 @@ + +//----------------------------------------------------------------------- +// +// * Copyright (C) 2021 KEHAIDASOFT All Rights Reserved +// * version : 4.0.30319.42000 +// * author : khd by t4-2 +// +//----------------------------------------------------------------------- + +using System; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; + +namespace Khd.Core.Domain.Models +{ + + [Table("base_carmateriel")] + public class BaseCarmateriel + { + + [Key] + [Column("id")] + public Guid id { get; set; } + + /// + /// 小车id + /// + [Column("car_id")] + public Guid? carId { get; set; } + + /// + /// 小车编码 + /// + [Column("car_no")] + public string carNo { get; set; } + + /// + /// 小车名称 + /// + [Column("car_name")] + public string carName { get; set; } + + /// + /// 半成品条码 + /// + [Column("barcode")] + public string barcode { get; set; } + + [Column("is_delete")] + public int? isDelete { get; set; } + + [Column("create_time")] + public DateTime? createTime { get; set; } + + [Column("create_id")] + public Guid? createId { get; set; } + + [Column("create_by")] + public string createBy { get; set; } + + [Column("modify_time")] + public DateTime? modifyTime { get; set; } + + [Column("modify_id")] + public Guid? modifyId { get; set; } + + [Column("modify_by")] + public string modifyBy { get; set; } + + [Column("definefield3")] + public string definefield3 { get; set; } + + [Column("definefield1")] + public string definefield1 { get; set; } + + [Column("definefield2")] + public string definefield2 { get; set; } + } +} + diff --git a/src/Khd.Core.Domain/Models/BaseCarmateriellog.cs b/src/Khd.Core.Domain/Models/BaseCarmateriellog.cs new file mode 100644 index 0000000..6a80ff7 --- /dev/null +++ b/src/Khd.Core.Domain/Models/BaseCarmateriellog.cs @@ -0,0 +1,74 @@ + +//----------------------------------------------------------------------- +// +// * Copyright (C) 2021 KEHAIDASOFT All Rights Reserved +// * version : 4.0.30319.42000 +// * author : khd by t4-2 +// +//----------------------------------------------------------------------- + +using System; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; + +namespace Khd.Core.Domain.Models +{ + + [Table("base_carmateriellog")] + public class BaseCarmateriellog + { + + [Key] + [Column("id")] + public Guid id { get; set; } + + [Column("car_id")] + public Guid? carId { get; set; } + + [Column("car_no")] + public int? carNo { get; set; } + + [Column("car_name")] + public string carName { get; set; } + + [Column("materiel_id")] + public Guid? materielId { get; set; } + + [Column("materiel_no")] + public string materielNo { get; set; } + + [Column("materiel_name")] + public string materielName { get; set; } + + [Column("is_delete")] + public int? isDelete { get; set; } + + [Column("create_time")] + public DateTime? createTime { get; set; } + + [Column("create_id")] + public Guid? createId { get; set; } + + [Column("create_by")] + public string createBy { get; set; } + + [Column("modify_time")] + public DateTime? modifyTime { get; set; } + + [Column("modify_id")] + public Guid? modifyId { get; set; } + + [Column("modify_by")] + public string modifyBy { get; set; } + + [Column("definefield3")] + public string definefield3 { get; set; } + + [Column("definefield1")] + public string definefield1 { get; set; } + + [Column("definefield2")] + public string definefield2 { get; set; } + } +} + diff --git a/src/Khd.Core.Domain/Models/BaseCarmaterielup.cs b/src/Khd.Core.Domain/Models/BaseCarmaterielup.cs new file mode 100644 index 0000000..1f4a677 --- /dev/null +++ b/src/Khd.Core.Domain/Models/BaseCarmaterielup.cs @@ -0,0 +1,104 @@ + +//----------------------------------------------------------------------- +// +// * Copyright (C) 2021 KEHAIDASOFT All Rights Reserved +// * version : 4.0.30319.42000 +// * author : khd by t4-2 +// +//----------------------------------------------------------------------- + +using System; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; + +namespace Khd.Core.Domain.Models +{ + + [Table("base_carmaterielup")] + public class BaseCarmaterielup + { + + [Key] + [Column("id")] + public Guid id { get; set; } + + /// + /// 小车id + /// + [Column("car_id")] + public Guid? carId { get; set; } + + /// + /// 小车编号 + /// + [Column("car_no")] + public int? carNo { get; set; } + + /// + /// 小车名称 + /// + [Column("car_name")] + public string carName { get; set; } + + /// + /// 物料id + /// + [Column("materiel_id")] + public Guid? materielId { get; set; } + + /// + /// 物料编码 + /// + [Column("materiel_no")] + public string materielNo { get; set; } + + /// + /// 物料名称 + /// + [Column("materiel_name")] + public string materielName { get; set; } + + /// + /// 数量 + /// + [Column("materiel_num")] + public int? materielNum { get; set; } + + /// + /// 上件点 + /// + [Column("up_line")] + public int? upLine { get; set; } + + [Column("is_delete")] + public int? isDelete { get; set; } + + [Column("create_time")] + public DateTime? createTime { get; set; } + + [Column("create_id")] + public Guid? createId { get; set; } + + [Column("create_by")] + public string createBy { get; set; } + + [Column("modify_time")] + public DateTime? modifyTime { get; set; } + + [Column("modify_id")] + public Guid? modifyId { get; set; } + + [Column("modify_by")] + public string modifyBy { get; set; } + + [Column("definefield3")] + public string definefield3 { get; set; } + + [Column("definefield1")] + public string definefield1 { get; set; } + + [Column("definefield2")] + public string definefield2 { get; set; } + } +} + diff --git a/src/Khd.Core.Domain/Models/BaseCarmaterielupdown.cs b/src/Khd.Core.Domain/Models/BaseCarmaterielupdown.cs new file mode 100644 index 0000000..8639489 --- /dev/null +++ b/src/Khd.Core.Domain/Models/BaseCarmaterielupdown.cs @@ -0,0 +1,110 @@ + +//----------------------------------------------------------------------- +// +// * Copyright (C) 2021 KEHAIDASOFT All Rights Reserved +// * version : 4.0.30319.42000 +// * author : khd by t4-2 +// +//----------------------------------------------------------------------- + +using System; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; + +namespace Khd.Core.Domain.Models +{ + + [Table("base_carmaterielupdown")] + public class BaseCarmaterielupdown + { + + [Key] + [Column("id")] + public Guid id { get; set; } + + /// + /// 小车id + /// + [Column("car_id")] + public Guid? carId { get; set; } + + /// + /// 小车编号 + /// + [Column("car_no")] + public int? carNo { get; set; } + + /// + /// 小车名称 + /// + [Column("car_name")] + public string carName { get; set; } + + /// + /// 物料id + /// + [Column("materiel_id")] + public Guid? materielId { get; set; } + + /// + /// 物料编码 + /// + [Column("materiel_no")] + public string materielNo { get; set; } + + /// + /// 物料名称 + /// + [Column("materiel_name")] + public string materielName { get; set; } + + /// + /// 数量 + /// + [Column("materiel_num")] + public int? materielNum { get; set; } + + /// + /// 线体 + /// + [Column("line")] + public int? line { get; set; } + + /// + /// 订单号 + /// + [Column("order_code")] + public string orderCode { get; set; } + + [Column("is_delete")] + public int? isDelete { get; set; } + + [Column("create_time")] + public DateTime? createTime { get; set; } + + [Column("create_id")] + public Guid? createId { get; set; } + + [Column("create_by")] + public string createBy { get; set; } + + [Column("modify_time")] + public DateTime? modifyTime { get; set; } + + [Column("modify_id")] + public Guid? modifyId { get; set; } + + [Column("modify_by")] + public string modifyBy { get; set; } + + [Column("definefield3")] + public string definefield3 { get; set; } + + [Column("definefield1")] + public string definefield1 { get; set; } + + [Column("definefield2")] + public string definefield2 { get; set; } + } +} + diff --git a/src/Khd.Core.Domain/Models/BaseCarorder.cs b/src/Khd.Core.Domain/Models/BaseCarorder.cs new file mode 100644 index 0000000..ee3b227 --- /dev/null +++ b/src/Khd.Core.Domain/Models/BaseCarorder.cs @@ -0,0 +1,31 @@ + +//----------------------------------------------------------------------- +// +// * Copyright (C) 2021 KEHAIDASOFT All Rights Reserved +// * version : 4.0.30319.42000 +// * author : khd by t4-2 +// +//----------------------------------------------------------------------- + +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; + +namespace Khd.Core.Domain.Models +{ + + [Table("base_carorder")] + public class BaseCarorder + { + + [Key] + [Column("car_no")] + public int carNo { get; set; } + + [Column("materiel_num")] + public int? materielNum { get; set; } + + [Column("order_id")] + public string orderId { get; set; } + } +} + diff --git a/src/Khd.Core.Domain/Models/BaseCarorderlist.cs b/src/Khd.Core.Domain/Models/BaseCarorderlist.cs new file mode 100644 index 0000000..98b374f --- /dev/null +++ b/src/Khd.Core.Domain/Models/BaseCarorderlist.cs @@ -0,0 +1,62 @@ + +//----------------------------------------------------------------------- +// +// * Copyright (C) 2021 KEHAIDASOFT All Rights Reserved +// * version : 4.0.30319.42000 +// * author : khd by t4-2 +// +//----------------------------------------------------------------------- + +using System; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; + +namespace Khd.Core.Domain.Models +{ + + [Table("base_carorderlist")] + public class BaseCarorderlist + { + + [Key] + [Column("id")] + public Guid id { get; set; } + + [Column("order_code")] + public string orderCode { get; set; } + + [Column("materiel_num")] + public int? materielNum { get; set; } + + [Column("materiel_no")] + public string materielNo { get; set; } + + [Column("prod_code")] + public string prodCode { get; set; } + + [Column("line_name")] + public string lineName { get; set; } + + [Column("est")] + public string est { get; set; } + + [Column("production_sequence")] + public string productionSequence { get; set; } + + [Column("Quantity")] + public string quantity { get; set; } + + [Column("UpQuantity")] + public string upquantity { get; set; } + + [Column("OutWareHouseQuantity")] + public string outwarehousequantity { get; set; } + + [Column("DownQuantity")] + public string downquantity { get; set; } + + [Column("IsOver")] + public string isover { get; set; } + } +} + diff --git a/src/Khd.Core.Domain/Models/BaseCarordernum.cs b/src/Khd.Core.Domain/Models/BaseCarordernum.cs new file mode 100644 index 0000000..27570ca --- /dev/null +++ b/src/Khd.Core.Domain/Models/BaseCarordernum.cs @@ -0,0 +1,80 @@ + +//----------------------------------------------------------------------- +// +// * Copyright (C) 2021 KEHAIDASOFT All Rights Reserved +// * version : 4.0.30319.42000 +// * author : khd by t4-2 +// +//----------------------------------------------------------------------- + +using System; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; + +namespace Khd.Core.Domain.Models +{ + + [Table("base_carordernum")] + public class BaseCarordernum + { + + [Key] + [Column("id")] + public Guid id { get; set; } + + /// + /// 小车id + /// + [Column("car_id")] + public Guid? carId { get; set; } + + /// + /// 小车编码 + /// + [Column("car_no")] + public string carNo { get; set; } + + /// + /// 小车名称 + /// + [Column("car_name")] + public string carName { get; set; } + + /// + /// 物料id + /// + [Column("materiel_id")] + public Guid? materielId { get; set; } + + /// + /// 物料编码 + /// + [Column("materiel_no")] + public string materielNo { get; set; } + + /// + /// 物料名称 + /// + [Column("materiel_name")] + public string materielName { get; set; } + + /// + /// 物料扫描数量 + /// + [Column("materiel_num")] + public int? materielNum { get; set; } + + [Column("order_code")] + public string orderCode { get; set; } + + [Column("type")] + public string type { get; set; } + + [Column("create_time")] + public DateTime? createTime { get; set; } + + [Column("order_num")] + public int? orderNum { get; set; } + } +} + diff --git a/src/Khd.Core.Domain/Models/BaseCarordernumnew.cs b/src/Khd.Core.Domain/Models/BaseCarordernumnew.cs new file mode 100644 index 0000000..09cf2df --- /dev/null +++ b/src/Khd.Core.Domain/Models/BaseCarordernumnew.cs @@ -0,0 +1,80 @@ + +//----------------------------------------------------------------------- +// +// * Copyright (C) 2021 KEHAIDASOFT All Rights Reserved +// * version : 4.0.30319.42000 +// * author : khd by t4-2 +// +//----------------------------------------------------------------------- + +using System; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; + +namespace Khd.Core.Domain.Models +{ + + [Table("base_carordernumnew")] + public class BaseCarordernumnew + { + + [Key] + [Column("id")] + public Guid id { get; set; } + + /// + /// 小车id + /// + [Column("car_id")] + public Guid? carId { get; set; } + + /// + /// 小车编码 + /// + [Column("car_no")] + public string carNo { get; set; } + + /// + /// 小车名称 + /// + [Column("car_name")] + public string carName { get; set; } + + /// + /// 物料id + /// + [Column("materiel_id")] + public Guid? materielId { get; set; } + + /// + /// 物料编码 + /// + [Column("materiel_no")] + public string materielNo { get; set; } + + /// + /// 物料名称 + /// + [Column("materiel_name")] + public string materielName { get; set; } + + /// + /// 物料扫描数量 + /// + [Column("materiel_num")] + public int? materielNum { get; set; } + + [Column("order_code")] + public string orderCode { get; set; } + + [Column("type")] + public string type { get; set; } + + [Column("create_time")] + public DateTime? createTime { get; set; } + + [Column("order_num")] + public int? orderNum { get; set; } + } +} + diff --git a/src/Khd.Core.Domain/Models/BaseCarpreline.cs b/src/Khd.Core.Domain/Models/BaseCarpreline.cs new file mode 100644 index 0000000..84dc61d --- /dev/null +++ b/src/Khd.Core.Domain/Models/BaseCarpreline.cs @@ -0,0 +1,122 @@ + +//----------------------------------------------------------------------- +// +// * Copyright (C) 2021 KEHAIDASOFT All Rights Reserved +// * version : 4.0.30319.42000 +// * author : khd by t4-2 +// +//----------------------------------------------------------------------- + +using System; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; + +namespace Khd.Core.Domain.Models +{ + + [Table("base_carpreline")] + public class BaseCarpreline + { + + [Key] + [Column("id")] + public Guid id { get; set; } + + [Column("car_id")] + public Guid? carId { get; set; } + + /// + /// 小车编码 + /// + [Column("car_no")] + public int? carNo { get; set; } + + /// + /// 小车名称 + /// + [Column("car_name")] + public string carName { get; set; } + + [Column("preline_id")] + public Guid? prelineId { get; set; } + + /// + /// 预设线编码 + /// + [Column("preline_no")] + public string prelineNo { get; set; } + + /// + /// 预设线名称 + /// + [Column("preline_nm")] + public string prelineNm { get; set; } + + /// + /// 站台分流线id + /// + [Column("sitenode_id")] + public Guid? sitenodeId { get; set; } + + /// + /// 顺序号 + /// + [Column("order_index")] + public int? orderIndex { get; set; } + + /// + /// 站台运输时间 + /// + [Column("duration_time")] + public int? durationTime { get; set; } + + /// + /// 站台转换类型(预留拓展) + /// + [Column("change_type")] + public int? changeType { get; set; } + + /// + /// plc写入值 + /// + [Column("plc_value")] + public string plcValue { get; set; } + + /// + /// 是否入库1入库0非入库 + /// + [Column("IsInStock")] + public int? isinstock { get; set; } + + [Column("is_delete")] + public int? isDelete { get; set; } + + [Column("create_time")] + public DateTime? createTime { get; set; } + + [Column("create_id")] + public Guid? createId { get; set; } + + [Column("create_by")] + public string createBy { get; set; } + + [Column("modify_time")] + public DateTime? modifyTime { get; set; } + + [Column("modify_id")] + public Guid? modifyId { get; set; } + + [Column("modify_by")] + public string modifyBy { get; set; } + + [Column("definefield3")] + public string definefield3 { get; set; } + + [Column("definefield1")] + public string definefield1 { get; set; } + + [Column("definefield2")] + public string definefield2 { get; set; } + } +} + diff --git a/src/Khd.Core.Domain/Models/BaseCarproduct.cs b/src/Khd.Core.Domain/Models/BaseCarproduct.cs new file mode 100644 index 0000000..6b0e99f --- /dev/null +++ b/src/Khd.Core.Domain/Models/BaseCarproduct.cs @@ -0,0 +1,47 @@ + +//----------------------------------------------------------------------- +// +// * Copyright (C) 2021 KEHAIDASOFT All Rights Reserved +// * version : 4.0.30319.42000 +// * author : khd by t4-2 +// +//----------------------------------------------------------------------- + +using System; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; + +namespace Khd.Core.Domain.Models +{ + + [Table("base_carproduct")] + public class BaseCarproduct + { + + [Key] + [Column("id")] + public Guid id { get; set; } + + [Column("car_id")] + public Guid? carId { get; set; } + + [Column("car_no")] + public int? carNo { get; set; } + + [Column("materiel_num")] + public int? materielNum { get; set; } + + [Column("order_code")] + public string orderCode { get; set; } + + [Column("materiel_id")] + public Guid? materielId { get; set; } + + [Column("materiel_no")] + public string materielNo { get; set; } + + [Column("line_code")] + public string lineCode { get; set; } + } +} + diff --git a/src/Khd.Core.Domain/Models/BaseCarrier.cs b/src/Khd.Core.Domain/Models/BaseCarrier.cs new file mode 100644 index 0000000..3a1cfad --- /dev/null +++ b/src/Khd.Core.Domain/Models/BaseCarrier.cs @@ -0,0 +1,86 @@ + +//----------------------------------------------------------------------- +// +// * Copyright (C) 2021 KEHAIDASOFT All Rights Reserved +// * version : 4.0.30319.42000 +// * author : khd by t4-2 +// +//----------------------------------------------------------------------- + +using System; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; + +namespace Khd.Core.Domain.Models +{ + + [Table("base_carrier")] + public class BaseCarrier + { + + [Key] + [Column("id")] + public Guid id { get; set; } + + /// + /// 货笼编码 + /// + [Column("carrier_no")] + public string carrierNo { get; set; } + + /// + /// 货笼名称 + /// + [Column("carrier_name")] + public string carrierName { get; set; } + + /// + /// RFID编码 + /// + [Column("carrier_rfid_no")] + public string carrierRfidNo { get; set; } + + /// + /// 颜色 + /// + [Column("carrier_color")] + public string carrierColor { get; set; } + + /// + /// 当前状态 + /// + [Column("carrier_status")] + public int? carrierStatus { get; set; } + + [Column("is_delete")] + public int? isDelete { get; set; } + + [Column("create_time")] + public DateTime? createTime { get; set; } + + [Column("create_id")] + public Guid? createId { get; set; } + + [Column("create_by")] + public string createBy { get; set; } + + [Column("modify_time")] + public DateTime? modifyTime { get; set; } + + [Column("modify_id")] + public Guid? modifyId { get; set; } + + [Column("modify_by")] + public string modifyBy { get; set; } + + [Column("definefield3")] + public string definefield3 { get; set; } + + [Column("definefield1")] + public string definefield1 { get; set; } + + [Column("definefield2")] + public string definefield2 { get; set; } + } +} + diff --git a/src/Khd.Core.Domain/Models/BaseCarthrough.cs b/src/Khd.Core.Domain/Models/BaseCarthrough.cs new file mode 100644 index 0000000..e4a69fd --- /dev/null +++ b/src/Khd.Core.Domain/Models/BaseCarthrough.cs @@ -0,0 +1,74 @@ + +//----------------------------------------------------------------------- +// +// * Copyright (C) 2021 KEHAIDASOFT All Rights Reserved +// * version : 4.0.30319.42000 +// * author : khd by t4-2 +// +//----------------------------------------------------------------------- + +using System; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; + +namespace Khd.Core.Domain.Models +{ + + [Table("base_carthrough")] + public class BaseCarthrough + { + + [Key] + [Column("id")] + public Guid id { get; set; } + + /// + /// 小车号 + /// + [Column("car_no")] + public int? carNo { get; set; } + + /// + /// 上件点 + /// + [Column("UpLine")] + public int? upline { get; set; } + + /// + /// 下件点 + /// + [Column("DownLine")] + public int? downline { get; set; } + + [Column("is_delete")] + public int? isDelete { get; set; } + + [Column("create_time")] + public DateTime? createTime { get; set; } + + [Column("create_id")] + public Guid? createId { get; set; } + + [Column("create_by")] + public string createBy { get; set; } + + [Column("modify_time")] + public DateTime? modifyTime { get; set; } + + [Column("modify_id")] + public Guid? modifyId { get; set; } + + [Column("modify_by")] + public string modifyBy { get; set; } + + [Column("definefield3")] + public string definefield3 { get; set; } + + [Column("definefield1")] + public string definefield1 { get; set; } + + [Column("definefield2")] + public string definefield2 { get; set; } + } +} + diff --git a/src/Khd.Core.Domain/Models/BaseDictionary.cs b/src/Khd.Core.Domain/Models/BaseDictionary.cs new file mode 100644 index 0000000..6ce9a9a --- /dev/null +++ b/src/Khd.Core.Domain/Models/BaseDictionary.cs @@ -0,0 +1,116 @@ + +//----------------------------------------------------------------------- +// +// * Copyright (C) 2021 KEHAIDASOFT All Rights Reserved +// * version : 4.0.30319.42000 +// * author : khd by t4-2 +// +//----------------------------------------------------------------------- + +using System; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; + +namespace Khd.Core.Domain.Models +{ + + [Table("wcs_base_dictionary")] + public class BaseDictionary + { + + [Key] + [Column("objid")] + public long objid { get; set; } + + /// + /// 字典名 + /// + [Column("dic_name")] + public string dicName { get; set; } + + /// + /// 字段名 + /// + [Column("dic_field")] + public string dicField { get; set; } + + /// + /// 对应名 + /// + [Column("dic_key")] + public string dicKey { get; set; } + + /// + /// 对应值 + /// + [Column("dic_value")] + public string dicValue { get; set; } + + /// + /// 排序 + /// + [Column("dic_sort")] + public string dicSort { get; set; } + + /// + /// 是否允许编辑 1允许 0不允许 + /// + [Column("is_edit")] + public int? isEdit { get; set; } + + /// + /// 是否可用 0:不可用 1:可用 + /// + [Column("use_flag")] + public int? useFlag { get; set; } + + /// + /// 创建者 + /// + [Column("create_by")] + public string createBy { get; set; } + + /// + /// 创建时间 + /// + [Column("create_time")] + public DateTime? createTime { get; set; } + + /// + /// 更新者 + /// + [Column("update_by")] + public string updateBy { get; set; } + + /// + /// 更新时间 + /// + [Column("update_time")] + public DateTime? updateTime { get; set; } + + /// + /// 备用字段1 + /// + [Column("agv_type")] + public string agvType { get; set; } + + /// + /// 备用字段2 + /// + [Column("agv_task_type")] + public string agvTaskType { get; set; } + + /// + /// 备用字段3 + /// + [Column("to_plc")] + public string ToPlc { get; set; } + + /// + /// 备注 + /// + [Column("remark")] + public string remark { get; set; } + } +} + diff --git a/src/Khd.Core.Domain/Models/BaseDowncarorderback.cs b/src/Khd.Core.Domain/Models/BaseDowncarorderback.cs new file mode 100644 index 0000000..1da46fb --- /dev/null +++ b/src/Khd.Core.Domain/Models/BaseDowncarorderback.cs @@ -0,0 +1,110 @@ + +//----------------------------------------------------------------------- +// +// * Copyright (C) 2021 KEHAIDASOFT All Rights Reserved +// * version : 4.0.30319.42000 +// * author : khd by t4-2 +// +//----------------------------------------------------------------------- + +using System; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; + +namespace Khd.Core.Domain.Models +{ + + [Table("base_downcarorderback")] + public class BaseDowncarorderback + { + + [Key] + [Column("id")] + public Guid id { get; set; } + + /// + /// 小车id + /// + [Column("car_id")] + public Guid? carId { get; set; } + + /// + /// 小车编码 + /// + [Column("car_no")] + public string carNo { get; set; } + + /// + /// 小车名称 + /// + [Column("car_name")] + public string carName { get; set; } + + /// + /// 订单号 + /// + [Column("order_id")] + public string orderId { get; set; } + + /// + /// 线体 + /// + [Column("line_code")] + public string lineCode { get; set; } + + /// + /// 物料id + /// + [Column("materiel_id")] + public Guid? materielId { get; set; } + + /// + /// 物料编码 + /// + [Column("materiel_no")] + public string materielNo { get; set; } + + /// + /// 物料名称 + /// + [Column("materiel_name")] + public string materielName { get; set; } + + /// + /// 数量 + /// + [Column("materiel_num")] + public int? materielNum { get; set; } + + [Column("is_delete")] + public int? isDelete { get; set; } + + [Column("create_time")] + public DateTime? createTime { get; set; } + + [Column("create_id")] + public Guid? createId { get; set; } + + [Column("create_by")] + public string createBy { get; set; } + + [Column("modify_time")] + public DateTime? modifyTime { get; set; } + + [Column("modify_id")] + public Guid? modifyId { get; set; } + + [Column("modify_by")] + public string modifyBy { get; set; } + + [Column("definefield3")] + public string definefield3 { get; set; } + + [Column("definefield1")] + public string definefield1 { get; set; } + + [Column("definefield2")] + public string definefield2 { get; set; } + } +} + diff --git a/src/Khd.Core.Domain/Models/BaseDownline.cs b/src/Khd.Core.Domain/Models/BaseDownline.cs new file mode 100644 index 0000000..e565d9c --- /dev/null +++ b/src/Khd.Core.Domain/Models/BaseDownline.cs @@ -0,0 +1,122 @@ + +//----------------------------------------------------------------------- +// +// * Copyright (C) 2021 KEHAIDASOFT All Rights Reserved +// * version : 4.0.30319.42000 +// * author : khd by t4-2 +// +//----------------------------------------------------------------------- + +using System; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; + +namespace Khd.Core.Domain.Models +{ + + [Table("base_downline")] + public class BaseDownline + { + + [Key] + [Column("id")] + public Guid id { get; set; } + + /// + /// 库区线id + /// + [Column("area_id")] + public Guid? areaId { get; set; } + + /// + /// 库区线编码 + /// + [Column("area_no")] + public string areaNo { get; set; } + + /// + /// 库区线名称 + /// + [Column("area_name")] + public string areaName { get; set; } + + /// + /// 小车id + /// + [Column("car_id")] + public Guid? carId { get; set; } + + /// + /// 小车编码 + /// + [Column("car_no")] + public string carNo { get; set; } + + /// + /// 小车名称 + /// + [Column("car_name")] + public string carName { get; set; } + + /// + /// 物料id + /// + [Column("materiel_id")] + public Guid? materielId { get; set; } + + /// + /// 物料编码 + /// + [Column("materiel_no")] + public string materielNo { get; set; } + + /// + /// 物料名称 + /// + [Column("materiel_name")] + public string materielName { get; set; } + + /// + /// 物料扫描数量 + /// + [Column("materiel_num")] + public int? materielNum { get; set; } + + /// + /// 1下件2倒库 + /// + [Column("run_type")] + public int? runType { get; set; } + + [Column("is_delete")] + public int? isDelete { get; set; } + + [Column("create_time")] + public DateTime? createTime { get; set; } + + [Column("create_id")] + public Guid? createId { get; set; } + + [Column("create_by")] + public string createBy { get; set; } + + [Column("modify_time")] + public DateTime? modifyTime { get; set; } + + [Column("modify_id")] + public Guid? modifyId { get; set; } + + [Column("modify_by")] + public string modifyBy { get; set; } + + [Column("definefield3")] + public string definefield3 { get; set; } + + [Column("definefield1")] + public string definefield1 { get; set; } + + [Column("definefield2")] + public string definefield2 { get; set; } + } +} + diff --git a/src/Khd.Core.Domain/Models/BaseEquip.cs b/src/Khd.Core.Domain/Models/BaseEquip.cs new file mode 100644 index 0000000..86c866c --- /dev/null +++ b/src/Khd.Core.Domain/Models/BaseEquip.cs @@ -0,0 +1,140 @@ + +//----------------------------------------------------------------------- +// +// * Copyright (C) 2021 KEHAIDASOFT All Rights Reserved +// * version : 4.0.30319.42000 +// * author : khd by t4-2 +// +//----------------------------------------------------------------------- + +using System; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; + +namespace Khd.Core.Domain.Models +{ + + [Table("wcs_base_equip")] + public class BaseEquip + { + [Column("endStationCode")] + public string endStationCode { get; set; } + [Column("container_no")] + public string containerNo { get; set; } + + [Column("empty_count")] + public int? emptyCount { get; set; } + + [Column("agv_position_code")] + public string agvPositionCode { get; set; } + + [Key] + [Column("objid")] + public long objid { get; set; } + + /// + /// 所属仓库 + /// + [Column("warehouse_id")] + public long? warehouseId { get; set; } + + /// + /// 设备编号 + /// + [Column("equip_no")] + public string equipNo { get; set; } + + /// + /// 设备名称 + /// + [Column("equip_name")] + public string equipName { get; set; } + + /// + /// 设备类型 1输送线 2 提升机 3 分拣输送线 + /// + [Column("equip_type")] + public int? equipType { get; set; } + + /// + /// IP地址 + /// + [Column("server_ip")] + public string serverIp { get; set; } + + /// + /// 端口 + /// + [Column("server_port")] + public int? serverPort { get; set; } + + /// + /// 设备状态,字典表 + /// + [Column("equip_status")] + public int? equipStatus { get; set; } + + /// + /// 所属楼层 + /// + [Column("floor_no")] + public int? floorNo { get; set; } + + /// + /// 是否可用 0:不可用 1:可用 + /// + [Column("use_flag")] + public int? useFlag { get; set; } + + /// + /// 创建者 + /// + [Column("create_by")] + public string createBy { get; set; } + + /// + /// 创建时间 + /// + [Column("create_time")] + public DateTime? createTime { get; set; } + + /// + /// 更新者 + /// + [Column("update_by")] + public string updateBy { get; set; } + + /// + /// 更新时间 + /// + [Column("update_time")] + public DateTime? updateTime { get; set; } + + /// + /// 备用字段1 + /// + [Column("ud1")] + public string ud1 { get; set; } + + /// + /// 备用字段2 + /// + [Column("ud2")] + public string ud2 { get; set; } + + /// + /// 备用字段3 + /// + [Column("ud3")] + public string ud3 { get; set; } + + /// + /// 备注 + /// + [Column("remark")] + public string remark { get; set; } + [Column("is_out")] + public int? IsOut { get; set; } + } +} + diff --git a/src/Khd.Core.Domain/Models/BaseEquipment.cs b/src/Khd.Core.Domain/Models/BaseEquipment.cs new file mode 100644 index 0000000..3179379 --- /dev/null +++ b/src/Khd.Core.Domain/Models/BaseEquipment.cs @@ -0,0 +1,86 @@ + +//----------------------------------------------------------------------- +// +// * Copyright (C) 2021 KEHAIDASOFT All Rights Reserved +// * version : 4.0.30319.42000 +// * author : khd by t4-2 +// +//----------------------------------------------------------------------- + +using System; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; + +namespace Khd.Core.Domain.Models +{ + + [Table("base_equipment")] + public class BaseEquipment + { + + [Key] + [Column("id")] + public Guid id { get; set; } + + /// + /// 设备编码 + /// + [Column("equipment_no")] + public string equipmentNo { get; set; } + + /// + /// 设备名称 + /// + [Column("equipment_name")] + public string equipmentName { get; set; } + + /// + /// 设备ip + /// + [Column("equipment_ip")] + public string equipmentIp { get; set; } + + /// + /// 设备品牌 + /// + [Column("equipment_spac")] + public string equipmentSpac { get; set; } + + /// + /// 设备类型 + /// + [Column("equipment_type")] + public int? equipmentType { get; set; } + + [Column("is_delete")] + public int? isDelete { get; set; } + + [Column("create_time")] + public DateTime? createTime { get; set; } + + [Column("create_id")] + public Guid? createId { get; set; } + + [Column("create_by")] + public string createBy { get; set; } + + [Column("modify_time")] + public DateTime? modifyTime { get; set; } + + [Column("modify_id")] + public Guid? modifyId { get; set; } + + [Column("modify_by")] + public string modifyBy { get; set; } + + [Column("definefield3")] + public string definefield3 { get; set; } + + [Column("definefield1")] + public string definefield1 { get; set; } + + [Column("definefield2")] + public string definefield2 { get; set; } + } +} + diff --git a/src/Khd.Core.Domain/Models/BaseFactory.cs b/src/Khd.Core.Domain/Models/BaseFactory.cs new file mode 100644 index 0000000..b2b4563 --- /dev/null +++ b/src/Khd.Core.Domain/Models/BaseFactory.cs @@ -0,0 +1,68 @@ + +//----------------------------------------------------------------------- +// +// * Copyright (C) 2021 KEHAIDASOFT All Rights Reserved +// * version : 4.0.30319.42000 +// * author : khd by t4-2 +// +//----------------------------------------------------------------------- + +using System; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; + +namespace Khd.Core.Domain.Models +{ + + [Table("base_factory")] + public class BaseFactory + { + + [Key] + [Column("id")] + public Guid id { get; set; } + + /// + /// 工厂编码 + /// + [Column("factory_no")] + public string factoryNo { get; set; } + + /// + /// 工厂名称 + /// + [Column("factory_name")] + public string factoryName { get; set; } + + [Column("is_delete")] + public int? isDelete { get; set; } + + [Column("create_time")] + public DateTime? createTime { get; set; } + + [Column("create_id")] + public Guid? createId { get; set; } + + [Column("create_by")] + public string createBy { get; set; } + + [Column("modify_time")] + public DateTime? modifyTime { get; set; } + + [Column("modify_id")] + public Guid? modifyId { get; set; } + + [Column("modify_by")] + public string modifyBy { get; set; } + + [Column("definefield3")] + public string definefield3 { get; set; } + + [Column("definefield1")] + public string definefield1 { get; set; } + + [Column("definefield2")] + public string definefield2 { get; set; } + } +} + diff --git a/src/Khd.Core.Domain/Models/BaseFaultlog.cs b/src/Khd.Core.Domain/Models/BaseFaultlog.cs new file mode 100644 index 0000000..73a6be6 --- /dev/null +++ b/src/Khd.Core.Domain/Models/BaseFaultlog.cs @@ -0,0 +1,86 @@ + +//----------------------------------------------------------------------- +// +// * Copyright (C) 2021 KEHAIDASOFT All Rights Reserved +// * version : 4.0.30319.42000 +// * author : khd by t4-2 +// +//----------------------------------------------------------------------- + +using System; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; + +namespace Khd.Core.Domain.Models +{ + + [Table("base_faultlog")] + public class BaseFaultlog + { + + [Key] + [Column("id")] + public Guid id { get; set; } + + [Column("line")] + public int? line { get; set; } + + [Column("ddate")] + public DateTime? ddate { get; set; } + + [Column("hourtime")] + public int? hourtime { get; set; } + + [Column("mintime")] + public int? mintime { get; set; } + + [Column("mincreatetime")] + public DateTime? mincreatetime { get; set; } + + [Column("maxcreatetime")] + public DateTime? maxcreatetime { get; set; } + + [Column("faulthourtime")] + public int? faulthourtime { get; set; } + + [Column("faultmintime")] + public int? faultmintime { get; set; } + + [Column("rhourtime")] + public int? rhourtime { get; set; } + + [Column("rfaultmintime")] + public int? rfaultmintime { get; set; } + + [Column("is_delete")] + public int? isDelete { get; set; } + + [Column("create_time")] + public DateTime? createTime { get; set; } + + [Column("create_id")] + public Guid? createId { get; set; } + + [Column("create_by")] + public string createBy { get; set; } + + [Column("modify_time")] + public DateTime? modifyTime { get; set; } + + [Column("modify_id")] + public Guid? modifyId { get; set; } + + [Column("modify_by")] + public string modifyBy { get; set; } + + [Column("definefield3")] + public string definefield3 { get; set; } + + [Column("definefield1")] + public string definefield1 { get; set; } + + [Column("definefield2")] + public string definefield2 { get; set; } + } +} + diff --git a/src/Khd.Core.Domain/Models/BaseFaulttime.cs b/src/Khd.Core.Domain/Models/BaseFaulttime.cs new file mode 100644 index 0000000..9bc08e0 --- /dev/null +++ b/src/Khd.Core.Domain/Models/BaseFaulttime.cs @@ -0,0 +1,50 @@ + +//----------------------------------------------------------------------- +// +// * Copyright (C) 2021 KEHAIDASOFT All Rights Reserved +// * version : 4.0.30319.42000 +// * author : khd by t4-2 +// +//----------------------------------------------------------------------- + +using System; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; + +namespace Khd.Core.Domain.Models +{ + + [Table("base_faulttime")] + public class BaseFaulttime + { + + [Key] + [Column("id")] + public Guid id { get; set; } + + /// + /// 线体 + /// + [Column("line")] + public int? line { get; set; } + + /// + /// 日期 + /// + [Column("ddate")] + public DateTime? ddate { get; set; } + + /// + /// 开始时间 + /// + [Column("begintime")] + public DateTime? begintime { get; set; } + + /// + /// 结束时间 + /// + [Column("endtime")] + public DateTime? endtime { get; set; } + } +} + diff --git a/src/Khd.Core.Domain/Models/BaseFlag.cs b/src/Khd.Core.Domain/Models/BaseFlag.cs new file mode 100644 index 0000000..f6e0a00 --- /dev/null +++ b/src/Khd.Core.Domain/Models/BaseFlag.cs @@ -0,0 +1,80 @@ + +//----------------------------------------------------------------------- +// +// * Copyright (C) 2021 KEHAIDASOFT All Rights Reserved +// * version : 4.0.30319.42000 +// * author : khd by t4-2 +// +//----------------------------------------------------------------------- + +using System; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; + +namespace Khd.Core.Domain.Models +{ + + [Table("base_flag")] + public class BaseFlag + { + + [Key] + [Column("id")] + public Guid id { get; set; } + + /// + /// 编码 + /// + [Column("flag_no")] + public string flagNo { get; set; } + + /// + /// 名称 + /// + [Column("flag_name")] + public string flagName { get; set; } + + /// + /// 值 + /// + [Column("n_flag")] + public int? nFlag { get; set; } + + /// + /// 描述 + /// + [Column("flag_memo")] + public string flagMemo { get; set; } + + [Column("is_delete")] + public int? isDelete { get; set; } + + [Column("create_time")] + public DateTime? createTime { get; set; } + + [Column("create_id")] + public Guid? createId { get; set; } + + [Column("create_by")] + public string createBy { get; set; } + + [Column("modify_time")] + public DateTime? modifyTime { get; set; } + + [Column("modify_id")] + public Guid? modifyId { get; set; } + + [Column("modify_by")] + public string modifyBy { get; set; } + + [Column("definefield3")] + public string definefield3 { get; set; } + + [Column("definefield1")] + public string definefield1 { get; set; } + + [Column("definefield2")] + public string definefield2 { get; set; } + } +} + diff --git a/src/Khd.Core.Domain/Models/BaseFollowmessage.cs b/src/Khd.Core.Domain/Models/BaseFollowmessage.cs new file mode 100644 index 0000000..a477b95 --- /dev/null +++ b/src/Khd.Core.Domain/Models/BaseFollowmessage.cs @@ -0,0 +1,116 @@ + +//----------------------------------------------------------------------- +// +// * Copyright (C) 2021 KEHAIDASOFT All Rights Reserved +// * version : 4.0.30319.42000 +// * author : khd by t4-2 +// +//----------------------------------------------------------------------- + +using System; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; + +namespace Khd.Core.Domain.Models +{ + + [Table("base_followmessage")] + public class BaseFollowmessage + { + + [Key] + [Column("id")] + public string id { get; set; } + + /// + /// 父订单id + /// + [Column("sid")] + public string sid { get; set; } + + /// + /// 订单号 + /// + [Column("vin_code")] + public string vinCode { get; set; } + + /// + /// 任务上件站点 + /// + [Column("up_site")] + public string upSite { get; set; } + + /// + /// 任务下件站点 + /// + [Column("down_site")] + public string downSite { get; set; } + + /// + /// 挂具号 + /// + [Column("car_no")] + public int carNo { get; set; } + + /// + /// 产品名称 + /// + [Column("material_name")] + public string materialName { get; set; } + + /// + /// 生产线别 + /// + [Column("line_code")] + public string lineCode { get; set; } + + /// + /// 线别名称 + /// + [Column("line_name")] + public string lineName { get; set; } + + /// + /// 订单是否完成0未完成1完成 + /// + [Column("IsOver")] + public int? isover { get; set; } + + /// + /// 计划开始时间 + /// + [Column("est")] + public DateTime? est { get; set; } + + /// + /// 计划数量 + /// + [Column("Quantity")] + public int? quantity { get; set; } + + /// + /// 下线数量 + /// + [Column("ActualQuantity")] + public int? actualquantity { get; set; } + + /// + /// 订单生产顺序 + /// + [Column("production_sequence")] + public int? productionSequence { get; set; } + + /// + /// 创建人 + /// + [Column("create_by")] + public string createBy { get; set; } + + /// + /// 下线记录创建时间 + /// + [Column("create_date")] + public DateTime? createDate { get; set; } + } +} + diff --git a/src/Khd.Core.Domain/Models/BaseLinearea.cs b/src/Khd.Core.Domain/Models/BaseLinearea.cs new file mode 100644 index 0000000..e0bd3e4 --- /dev/null +++ b/src/Khd.Core.Domain/Models/BaseLinearea.cs @@ -0,0 +1,89 @@ + +//----------------------------------------------------------------------- +// +// * Copyright (C) 2021 KEHAIDASOFT All Rights Reserved +// * version : 4.0.30319.42000 +// * author : khd by t4-2 +// +//----------------------------------------------------------------------- + +using System; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; + +namespace Khd.Core.Domain.Models +{ + + [Table("base_linearea")] + public class BaseLinearea + { + + [Key] + [Column("id")] + public Guid id { get; set; } + + [Column("area_id")] + public Guid? areaId { get; set; } + + /// + /// 区域编码 + /// + [Column("area_no")] + public string areaNo { get; set; } + + /// + /// 区域名称 + /// + [Column("area_name")] + public string areaName { get; set; } + + /// + /// 产线id + /// + [Column("line_id")] + public Guid? lineId { get; set; } + + /// + /// 产线编码 + /// + [Column("line_no")] + public string lineNo { get; set; } + + /// + /// 产线名称 + /// + [Column("line_name")] + public string lineName { get; set; } + + [Column("is_delete")] + public int? isDelete { get; set; } + + [Column("create_time")] + public DateTime? createTime { get; set; } + + [Column("create_id")] + public Guid? createId { get; set; } + + [Column("create_by")] + public string createBy { get; set; } + + [Column("modify_time")] + public DateTime? modifyTime { get; set; } + + [Column("modify_id")] + public Guid? modifyId { get; set; } + + [Column("modify_by")] + public string modifyBy { get; set; } + + [Column("definefield3")] + public string definefield3 { get; set; } + + [Column("definefield1")] + public string definefield1 { get; set; } + + [Column("definefield2")] + public string definefield2 { get; set; } + } +} + diff --git a/src/Khd.Core.Domain/Models/BaseLineinfo.cs b/src/Khd.Core.Domain/Models/BaseLineinfo.cs new file mode 100644 index 0000000..8a07c6d --- /dev/null +++ b/src/Khd.Core.Domain/Models/BaseLineinfo.cs @@ -0,0 +1,86 @@ + +//----------------------------------------------------------------------- +// +// * Copyright (C) 2021 KEHAIDASOFT All Rights Reserved +// * version : 4.0.30319.42000 +// * author : khd by t4-2 +// +//----------------------------------------------------------------------- + +using System; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; + +namespace Khd.Core.Domain.Models +{ + + [Table("base_lineinfo")] + public class BaseLineinfo + { + + [Key] + [Column("id")] + public Guid id { get; set; } + + /// + /// 产线编码 + /// + [Column("line_no")] + public string lineNo { get; set; } + + /// + /// 产线名称 + /// + [Column("linen_ame")] + public string linenAme { get; set; } + + /// + /// 工厂名称 + /// + [Column("line_factory_name")] + public string lineFactoryName { get; set; } + + /// + /// 工厂编码 + /// + [Column("line_factory_no")] + public string lineFactoryNo { get; set; } + + /// + /// 工厂id + /// + [Column("line_factory_id")] + public Guid? lineFactoryId { get; set; } + + [Column("is_delete")] + public int? isDelete { get; set; } + + [Column("create_time")] + public DateTime? createTime { get; set; } + + [Column("create_id")] + public Guid? createId { get; set; } + + [Column("create_by")] + public string createBy { get; set; } + + [Column("modify_time")] + public DateTime? modifyTime { get; set; } + + [Column("modify_id")] + public Guid? modifyId { get; set; } + + [Column("modify_by")] + public string modifyBy { get; set; } + + [Column("definefield3")] + public string definefield3 { get; set; } + + [Column("definefield1")] + public string definefield1 { get; set; } + + [Column("definefield2")] + public string definefield2 { get; set; } + } +} + diff --git a/src/Khd.Core.Domain/Models/BaseLoginlog.cs b/src/Khd.Core.Domain/Models/BaseLoginlog.cs new file mode 100644 index 0000000..06e4408 --- /dev/null +++ b/src/Khd.Core.Domain/Models/BaseLoginlog.cs @@ -0,0 +1,74 @@ + +//----------------------------------------------------------------------- +// +// * Copyright (C) 2021 KEHAIDASOFT All Rights Reserved +// * version : 4.0.30319.42000 +// * author : khd by t4-2 +// +//----------------------------------------------------------------------- + +using System; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; + +namespace Khd.Core.Domain.Models +{ + + [Table("base_loginlog")] + public class BaseLoginlog + { + + [Key] + [Column("id")] + public Guid id { get; set; } + + /// + /// 站点 + /// + [Column("sitenode")] + public int? sitenode { get; set; } + + /// + /// 用户名 + /// + [Column("loginname")] + public string loginname { get; set; } + + /// + /// 姓名 + /// + [Column("fullname")] + public string fullname { get; set; } + + [Column("is_delete")] + public int? isDelete { get; set; } + + [Column("create_time")] + public DateTime? createTime { get; set; } + + [Column("create_id")] + public Guid? createId { get; set; } + + [Column("create_by")] + public string createBy { get; set; } + + [Column("modify_time")] + public DateTime? modifyTime { get; set; } + + [Column("modify_id")] + public Guid? modifyId { get; set; } + + [Column("modify_by")] + public string modifyBy { get; set; } + + [Column("definefield3")] + public string definefield3 { get; set; } + + [Column("definefield1")] + public string definefield1 { get; set; } + + [Column("definefield2")] + public string definefield2 { get; set; } + } +} + diff --git a/src/Khd.Core.Domain/Models/BaseMaterialinfo.cs b/src/Khd.Core.Domain/Models/BaseMaterialinfo.cs new file mode 100644 index 0000000..cf542fa --- /dev/null +++ b/src/Khd.Core.Domain/Models/BaseMaterialinfo.cs @@ -0,0 +1,92 @@ + +//----------------------------------------------------------------------- +// +// * Copyright (C) 2021 KEHAIDASOFT All Rights Reserved +// * version : 4.0.30319.42000 +// * author : khd by t4-2 +// +//----------------------------------------------------------------------- + +using System; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; + +namespace Khd.Core.Domain.Models +{ + + [Table("base_materialinfo")] + public class BaseMaterialinfo + { + + [Key] + [Column("id")] + public Guid? id { get; set; } + + /// + /// 物料编码 + /// + [Column("material_no")] + public string materialNo { get; set; } + + /// + /// 物料名称 + /// + [Column("material_name")] + public string materialName { get; set; } + + /// + /// 1号上件点K46写入PLC长度,单位:mm + /// + [Column("k46up_length")] + public string k46upLength { get; set; } + + /// + /// 2号上件点K48写入PLC长度,单位:mm + /// + [Column("k48up_length")] + public string k48upLength { get; set; } + + /// + /// 下件写入PLC长度,单位:mm + /// + [Column("down_length")] + public string downLength { get; set; } + + /// + /// 物料类型 + /// + [Column("material_type")] + public string materialType { get; set; } + + [Column("is_delete")] + public int? isDelete { get; set; } + + [Column("create_id")] + public Guid? createId { get; set; } + + [Column("create_by")] + public string createBy { get; set; } + + [Column("create_time")] + public DateTime? createTime { get; set; } + + [Column("modify_id")] + public Guid? modifyId { get; set; } + + [Column("modify_by")] + public string modifyBy { get; set; } + + [Column("modify_time")] + public DateTime? modifyTime { get; set; } + + [Column("definefield1")] + public string definefield1 { get; set; } + + [Column("definefield2")] + public string definefield2 { get; set; } + + [Column("definefield3")] + public string definefield3 { get; set; } + } +} + diff --git a/src/Khd.Core.Domain/Models/BaseMaterialinfobom.cs b/src/Khd.Core.Domain/Models/BaseMaterialinfobom.cs new file mode 100644 index 0000000..2081519 --- /dev/null +++ b/src/Khd.Core.Domain/Models/BaseMaterialinfobom.cs @@ -0,0 +1,95 @@ + +//----------------------------------------------------------------------- +// +// * Copyright (C) 2021 KEHAIDASOFT All Rights Reserved +// * version : 4.0.30319.42000 +// * author : khd by t4-2 +// +//----------------------------------------------------------------------- + +using System; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; + +namespace Khd.Core.Domain.Models +{ + + [Table("base_materialinfobom")] + public class BaseMaterialinfobom + { + + [Key] + [Column("id")] + public Guid id { get; set; } + + /// + /// 成品id + /// + [Column("materiel_finish_id")] + public Guid? materielFinishId { get; set; } + + /// + /// 成品编码 + /// + [Column("materiel_finish_no")] + public string materielFinishNo { get; set; } + + /// + /// 成品名称 + /// + [Column("materiel_finish_name")] + public string materielFinishName { get; set; } + + /// + /// 箱体id + /// + [Column("materiel_box_id")] + public Guid? materielBoxId { get; set; } + + /// + /// 箱体编码 + /// + [Column("materiel_box_no")] + public string materielBoxNo { get; set; } + + /// + /// 箱体名称 + /// + [Column("materiel_box_name")] + public string materielBoxName { get; set; } + + [Column("version")] + public string version { get; set; } + + [Column("is_delete")] + public int? isDelete { get; set; } + + [Column("create_time")] + public DateTime? createTime { get; set; } + + [Column("create_id")] + public Guid? createId { get; set; } + + [Column("create_by")] + public string createBy { get; set; } + + [Column("modify_time")] + public DateTime? modifyTime { get; set; } + + [Column("modify_id")] + public Guid? modifyId { get; set; } + + [Column("modify_by")] + public string modifyBy { get; set; } + + [Column("definefield3")] + public string definefield3 { get; set; } + + [Column("definefield1")] + public string definefield1 { get; set; } + + [Column("definefield2")] + public string definefield2 { get; set; } + } +} + diff --git a/src/Khd.Core.Domain/Models/BaseOrderinfo.cs b/src/Khd.Core.Domain/Models/BaseOrderinfo.cs new file mode 100644 index 0000000..1c3fed5 --- /dev/null +++ b/src/Khd.Core.Domain/Models/BaseOrderinfo.cs @@ -0,0 +1,134 @@ + +//----------------------------------------------------------------------- +// +// * Copyright (C) 2021 KEHAIDASOFT All Rights Reserved +// * version : 4.0.30319.42000 +// * author : khd by t4-2 +// +//----------------------------------------------------------------------- + +using System; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; + +namespace Khd.Core.Domain.Models +{ + + [Table("base_orderinfo")] + public class BaseOrderinfo + { + + [Key] + [Column("id")] + public Guid id { get; set; } + + /// + /// 订单编码 + /// + [Column("order_no")] + public string orderNo { get; set; } + + /// + /// 物料id + /// + [Column("material_id")] + public Guid? materialId { get; set; } + + /// + /// 物料编码 + /// + [Column("material_no")] + public string materialNo { get; set; } + + /// + /// 线体id + /// + [Column("material_line_id")] + public Guid? materialLineId { get; set; } + + /// + /// 线体名称 + /// + [Column("material_line_name")] + public string materialLineName { get; set; } + + /// + /// 线体编码 + /// + [Column("material_line_no")] + public string materialLineNo { get; set; } + + /// + /// 时序顺序 + /// + [Column("product_sortno")] + public int? productSortno { get; set; } + + /// + /// 生产数量 + /// + [Column("product_amount")] + public int? productAmount { get; set; } + + /// + /// bom版本 + /// + [Column("bom_version")] + public string bomVersion { get; set; } + + /// + /// 订单日期 + /// + [Column("plan_starttime")] + public DateTime? planStarttime { get; set; } + + /// + /// 0未完成1已完成 + /// + [Column("plan_state")] + public int? planState { get; set; } + + /// + /// 上件数量 + /// + [Column("up_amount")] + public int? upAmount { get; set; } + + /// + /// 下件数量 + /// + [Column("down_amount")] + public int? downAmount { get; set; } + + [Column("is_delete")] + public int? isDelete { get; set; } + + [Column("create_time")] + public DateTime? createTime { get; set; } + + [Column("create_id")] + public Guid? createId { get; set; } + + [Column("create_by")] + public string createBy { get; set; } + + [Column("modify_time")] + public DateTime? modifyTime { get; set; } + + [Column("modify_id")] + public Guid? modifyId { get; set; } + + [Column("modify_by")] + public string modifyBy { get; set; } + + [Column("definefield3")] + public string definefield3 { get; set; } + + [Column("definefield1")] + public string definefield1 { get; set; } + + [Column("definefield2")] + public string definefield2 { get; set; } + } +} + diff --git a/src/Khd.Core.Domain/Models/BaseOrderlog.cs b/src/Khd.Core.Domain/Models/BaseOrderlog.cs new file mode 100644 index 0000000..79c162c --- /dev/null +++ b/src/Khd.Core.Domain/Models/BaseOrderlog.cs @@ -0,0 +1,35 @@ + +//----------------------------------------------------------------------- +// +// * Copyright (C) 2021 KEHAIDASOFT All Rights Reserved +// * version : 4.0.30319.42000 +// * author : khd by t4-2 +// +//----------------------------------------------------------------------- + +using System; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; + +namespace Khd.Core.Domain.Models +{ + + [Table("base_orderlog")] + public class BaseOrderlog + { + + [Key] + [Column("id")] + public Guid id { get; set; } + + [Column("updatememo")] + public string updatememo { get; set; } + + [Column("create_time")] + public DateTime? createTime { get; set; } + + [Column("type")] + public string type { get; set; } + } +} + diff --git a/src/Khd.Core.Domain/Models/BasePlc.cs b/src/Khd.Core.Domain/Models/BasePlc.cs new file mode 100644 index 0000000..80a3ca7 --- /dev/null +++ b/src/Khd.Core.Domain/Models/BasePlc.cs @@ -0,0 +1,26 @@ +using System.ComponentModel.DataAnnotations.Schema; + +namespace Khd.Core.Domain.Models +{ + [Table("wcs_plcpoint")] + public class BasePlc + { + [Column("id")] + public int Id { get; set; } + + [Column("name")] + public string Name { get; set; } + + [Column("station")] + public string Station { get; set; } + + [Column("address")] + public string Address { get; set; } + + [Column("value")] + public string Value { get; set; } + + [Column("type")] + public string type { get; set; } + } +} diff --git a/src/Khd.Core.Domain/Models/BasePlcpoint.cs b/src/Khd.Core.Domain/Models/BasePlcpoint.cs new file mode 100644 index 0000000..8610d8d --- /dev/null +++ b/src/Khd.Core.Domain/Models/BasePlcpoint.cs @@ -0,0 +1,116 @@ + +//----------------------------------------------------------------------- +// +// * Copyright (C) 2021 KEHAIDASOFT All Rights Reserved +// * version : 4.0.30319.42000 +// * author : khd by t4-2 +// +//----------------------------------------------------------------------- + +using System; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; + +namespace Khd.Core.Domain.Models +{ + + [Table("wcs_base_plcpoint")] + public class BasePlcpoint + { + + [Key] + [Column("id")] + public long? id { get; set; } + + /// + /// plc点位编码 + /// + [Column("plcpoint_no")] + public string plcpointNo { get; set; } + + /// + /// plc点位编名称 + /// + [Column("plcpoint_name")] + public string plcpointName { get; set; } + + /// + /// 点位长度 + /// + [Column("plcpoint_length")] + public int? plcpointLength { get; set; } + + /// + /// 点位地址 + /// + [Column("plcpoint_address")] + public string plcpointAddress { get; set; } + + /// + /// 设备id + /// + [Column("equipment_id")] + public long? equipmentId { get; set; } + + /// + /// 设备编码 + /// + [Column("equipment_no")] + public string equipmentNo { get; set; } + + /// + /// 设备名称 + /// + [Column("equipment_name")] + public string equipmentName { get; set; } + + /// + /// plc点位数据类型 + /// + [Column("plcpoint_type")] + public int? plcpointType { get; set; } + + /// + /// 站点id + /// + [Column("sitenode_id")] + public long? sitenodeId { get; set; } + + /// + /// 所属楼层 + /// + [Column("floor_no")] + public int? floorNo { get; set; } + + [Column("is_delete")] + public int? isDelete { get; set; } + + [Column("create_time")] + public DateTime? createTime { get; set; } + + [Column("create_id")] + public Guid? createId { get; set; } + + [Column("create_by")] + public string createBy { get; set; } + + [Column("modify_time")] + public DateTime? modifyTime { get; set; } + + [Column("modify_id")] + public Guid? modifyId { get; set; } + + [Column("modify_by")] + public string modifyBy { get; set; } + + [Column("definefield3")] + public string definefield3 { get; set; } + + [Column("definefield1")] + public string definefield1 { get; set; } + + [Column("definefield2")] + public string definefield2 { get; set; } + } +} + diff --git a/src/Khd.Core.Domain/Models/BasePlcpointsite.cs b/src/Khd.Core.Domain/Models/BasePlcpointsite.cs new file mode 100644 index 0000000..463d5e9 --- /dev/null +++ b/src/Khd.Core.Domain/Models/BasePlcpointsite.cs @@ -0,0 +1,95 @@ + +//----------------------------------------------------------------------- +// +// * Copyright (C) 2021 KEHAIDASOFT All Rights Reserved +// * version : 4.0.30319.42000 +// * author : khd by t4-2 +// +//----------------------------------------------------------------------- + +using System; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; + +namespace Khd.Core.Domain.Models +{ + + [Table("base_plcpointsite")] + public class BasePlcpointsite + { + + [Key] + [Column("id")] + public int id { get; set; } + + [Column("site_id")] + public Guid? siteId { get; set; } + + /// + /// 站点编码 + /// + [Column("site_no")] + public string siteNo { get; set; } + + /// + /// 站点名称 + /// + [Column("site_name")] + public string siteName { get; set; } + + /// + /// plcid + /// + [Column("plcpoint_id")] + public Guid? plcpointId { get; set; } + + /// + /// plc点编码 + /// + [Column("plcpoint_no")] + public string plcpointNo { get; set; } + + /// + /// plc点名称 + /// + [Column("plcpoint_name")] + public string plcpointName { get; set; } + + /// + /// plc点逻辑类型 + /// + [Column("plctype_id")] + public Guid? plctypeId { get; set; } + + [Column("is_delete")] + public int? isDelete { get; set; } + + [Column("create_time")] + public DateTime? createTime { get; set; } + + [Column("create_id")] + public Guid? createId { get; set; } + + [Column("create_by")] + public string createBy { get; set; } + + [Column("modify_time")] + public DateTime? modifyTime { get; set; } + + [Column("modify_id")] + public Guid? modifyId { get; set; } + + [Column("modify_by")] + public string modifyBy { get; set; } + + [Column("definefield3")] + public string definefield3 { get; set; } + + [Column("definefield1")] + public string definefield1 { get; set; } + + [Column("definefield2")] + public string definefield2 { get; set; } + } +} + diff --git a/src/Khd.Core.Domain/Models/BasePlctype.cs b/src/Khd.Core.Domain/Models/BasePlctype.cs new file mode 100644 index 0000000..259362f --- /dev/null +++ b/src/Khd.Core.Domain/Models/BasePlctype.cs @@ -0,0 +1,74 @@ + +//----------------------------------------------------------------------- +// +// * Copyright (C) 2021 KEHAIDASOFT All Rights Reserved +// * version : 4.0.30319.42000 +// * author : khd by t4-2 +// +//----------------------------------------------------------------------- + +using System; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; + +namespace Khd.Core.Domain.Models +{ + + [Table("base_plctype")] + public class BasePlctype + { + + [Key] + [Column("id")] + public Guid id { get; set; } + + /// + /// plc类型编码 + /// + [Column("plctype_no")] + public string plctypeNo { get; set; } + + /// + /// plc类型编名称 + /// + [Column("plctype_name")] + public string plctypeName { get; set; } + + /// + /// 指令内容 + /// + [Column("plctype_command")] + public string plctypeCommand { get; set; } + + [Column("is_delete")] + public int? isDelete { get; set; } + + [Column("create_time")] + public DateTime? createTime { get; set; } + + [Column("create_id")] + public Guid? createId { get; set; } + + [Column("create_by")] + public string createBy { get; set; } + + [Column("modify_time")] + public DateTime? modifyTime { get; set; } + + [Column("modify_id")] + public Guid? modifyId { get; set; } + + [Column("modify_by")] + public string modifyBy { get; set; } + + [Column("definefield3")] + public string definefield3 { get; set; } + + [Column("definefield1")] + public string definefield1 { get; set; } + + [Column("definefield2")] + public string definefield2 { get; set; } + } +} + diff --git a/src/Khd.Core.Domain/Models/BasePrelinedetail.cs b/src/Khd.Core.Domain/Models/BasePrelinedetail.cs new file mode 100644 index 0000000..b578aa4 --- /dev/null +++ b/src/Khd.Core.Domain/Models/BasePrelinedetail.cs @@ -0,0 +1,110 @@ + +//----------------------------------------------------------------------- +// +// * Copyright (C) 2021 KEHAIDASOFT All Rights Reserved +// * version : 4.0.30319.42000 +// * author : khd by t4-2 +// +//----------------------------------------------------------------------- + +using System; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; + +namespace Khd.Core.Domain.Models +{ + + [Table("base_prelinedetail")] + public class BasePrelinedetail + { + + [Key] + [Column("id")] + public Guid id { get; set; } + + [Column("preline_id")] + public Guid? prelineId { get; set; } + + /// + /// 预设线编码 + /// + [Column("preline_no")] + public string prelineNo { get; set; } + + /// + /// 预设线名称 + /// + [Column("preline_nm")] + public string prelineNm { get; set; } + + /// + /// 站台分流线id + /// + [Column("sitenode_id")] + public Guid? sitenodeId { get; set; } + + /// + /// 顺序号 + /// + [Column("order_index")] + public int? orderIndex { get; set; } + + /// + /// 站台运输时间 + /// + [Column("duration_time")] + public int? durationTime { get; set; } + + /// + /// 站台转换类型(预留拓展) + /// + [Column("change_type")] + public int? changeType { get; set; } + + /// + /// plc写入值 + /// + [Column("plc_value")] + public string plcValue { get; set; } + + /// + /// 1入库0非入库 + /// + [Column("IsInStock")] + public int? isinstock { get; set; } + + [Column("is_delete")] + public int? isDelete { get; set; } + + [Column("create_time")] + public DateTime? createTime { get; set; } + + [Column("create_id")] + public Guid? createId { get; set; } + + [Column("create_by")] + public string createBy { get; set; } + + [Column("modify_time")] + public DateTime? modifyTime { get; set; } + + [Column("modify_id")] + public Guid? modifyId { get; set; } + + [Column("modify_by")] + public string modifyBy { get; set; } + + [Column("definefield3")] + public string definefield3 { get; set; } + + [Column("definefield1")] + public string definefield1 { get; set; } + + [Column("definefield2")] + public string definefield2 { get; set; } + + [Column("line_id")] + public Guid? lineId { get; set; } + } +} + diff --git a/src/Khd.Core.Domain/Models/BasePrelineinfo.cs b/src/Khd.Core.Domain/Models/BasePrelineinfo.cs new file mode 100644 index 0000000..865e11c --- /dev/null +++ b/src/Khd.Core.Domain/Models/BasePrelineinfo.cs @@ -0,0 +1,113 @@ + +//----------------------------------------------------------------------- +// +// * Copyright (C) 2021 KEHAIDASOFT All Rights Reserved +// * version : 4.0.30319.42000 +// * author : khd by t4-2 +// +//----------------------------------------------------------------------- + +using System; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; + +namespace Khd.Core.Domain.Models +{ + + [Table("base_prelineinfo")] + public class BasePrelineinfo + { + + [Key] + [Column("id")] + public Guid id { get; set; } + + /// + /// 预设线编码 + /// + [Column("preline_no")] + public string prelineNo { get; set; } + + /// + /// 预设线名称 + /// + [Column("preline_nm")] + public string prelineNm { get; set; } + + /// + /// 开始站台 + /// + [Column("start_site")] + public Guid? startSite { get; set; } + + /// + /// 结束站台 + /// + [Column("end_site")] + public Guid? endSite { get; set; } + + /// + /// 预设送达时间(秒) + /// + [Column("plan_duration")] + public int? planDuration { get; set; } + + /// + /// 输送类型 1入库2下件3倒库4拉回 + /// + [Column("run_type")] + public int? runType { get; set; } + + /// + /// 库区 + /// + [Column("area_id")] + public Guid? areaId { get; set; } + + /// + /// 库区1,2 + /// + [Column("ware_house")] + public int? wareHouse { get; set; } + + /// + /// 501写1,502写2,503写3 + /// + [Column("down_line")] + public int? downLine { get; set; } + + [Column("is_delete")] + public int? isDelete { get; set; } + + [Column("create_time")] + public DateTime? createTime { get; set; } + + [Column("create_id")] + public Guid? createId { get; set; } + + [Column("create_by")] + public string createBy { get; set; } + + [Column("modify_time")] + public DateTime? modifyTime { get; set; } + + [Column("modify_id")] + public Guid? modifyId { get; set; } + + [Column("modify_by")] + public string modifyBy { get; set; } + + [Column("definefield3")] + public string definefield3 { get; set; } + + [Column("definefield1")] + public string definefield1 { get; set; } + + [Column("definefield2")] + public string definefield2 { get; set; } + + [Column("line_id")] + public Guid? lineId { get; set; } + } +} + diff --git a/src/Khd.Core.Domain/Models/BaseProductionOrderSplit.cs b/src/Khd.Core.Domain/Models/BaseProductionOrderSplit.cs new file mode 100644 index 0000000..2088921 --- /dev/null +++ b/src/Khd.Core.Domain/Models/BaseProductionOrderSplit.cs @@ -0,0 +1,203 @@ + +//----------------------------------------------------------------------- +// +// * Copyright (C) 2021 KEHAIDASOFT All Rights Reserved +// * version : 4.0.30319.42000 +// * author : khd by t4-2 +// +//----------------------------------------------------------------------- + +using System; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; + +namespace Khd.Core.Domain.Models +{ + + [Table("base_production_order_split")] + public class BaseProductionOrderSplit + { + + [Key] + [Column("id")] + public string id { get; set; } + + [Column("site_code")] + public string siteCode { get; set; } + + /// + /// 线体编码 + /// + [Column("line_code")] + public string lineCode { get; set; } + + /// + /// 线体名称 + /// + [Column("line_name")] + public string lineName { get; set; } + + /// + /// 订单号 + /// + [Column("order_code")] + public string orderCode { get; set; } + + /// + /// 产品编码 + /// + [Column("prod_code")] + public string prodCode { get; set; } + + /// + /// 产品名称 + /// + [Column("prod_desc")] + public string prodDesc { get; set; } + + /// + /// 计划开始时间 + /// + [Column("est")] + public DateTime? est { get; set; } + + /// + /// 计划数量 + /// + [Column("Quantity")] + public int? quantity { get; set; } + + /// + /// 可用计划数 + /// + [Column("available_quantity")] + public int? availableQuantity { get; set; } + + /// + /// 上线数量 + /// + [Column("online_quantity")] + public int? onlineQuantity { get; set; } + + /// + /// 下线数量 + /// + [Column("ActualQuantity")] + public int? actualquantity { get; set; } + + [Column("UpQuantity")] + public int? upquantity { get; set; } + + /// + /// 出库数量 + /// + [Column("OutWareHouseQuantity")] + public int? outwarehousequantity { get; set; } + + [Column("DownQuantity")] + public int? downquantity { get; set; } + + /// + /// 订单是否完成0未完成1完成 + /// + [Column("IsOver")] + public int? isover { get; set; } + + /// + /// 排产时间 + /// + [Column("scheduling_time")] + public DateTime? schedulingTime { get; set; } + + /// + /// 拆单状态:0正在拆单,1正常 + /// + [Column("split_status")] + public string splitStatus { get; set; } + + /// + /// 订单生产顺序 + /// + [Column("production_sequence")] + public int? productionSequence { get; set; } + + /// + /// 创建时间 + /// + [Column("create_date")] + public DateTime? createDate { get; set; } + + /// + /// 最后更新时间 + /// + [Column("last_update_date")] + public DateTime? lastUpdateDate { get; set; } + + /// + /// 创建人 + /// + [Column("create_by")] + public string createBy { get; set; } + + /// + /// 最后更新人 + /// + [Column("last_update_by")] + public string lastUpdateBy { get; set; } + + /// + /// 父订单id + /// + [Column("parent_order_id")] + public string parentOrderId { get; set; } + + /// + /// 0非源订单,1源订单 + /// + [Column("is_source")] + public string isSource { get; set; } + + /// + /// 0未同步,1已同步 + /// + [Column("is_sync")] + public string isSync { get; set; } + + /// + /// 0为未完成,1为已完成 + /// + [Column("is_completed")] + public string isCompleted { get; set; } + + /// + /// 企业编码 + /// + [Column("Enterprise_Code")] + public string enterpriseCode { get; set; } + + /// + /// 是否启用 + /// + [Column("Active")] + public string active { get; set; } + + /// + /// 工厂Id + /// + [Column("Site_Id")] + public string siteId { get; set; } + + /// + /// 企业Id + /// + [Column("Enterprise_Id")] + public string enterpriseId { get; set; } + + /// + /// 条码区间 + /// + [Column("min_max_barcode")] + public string minMaxBarcode { get; set; } + } +} + diff --git a/src/Khd.Core.Domain/Models/BaseProductionOrderSplitBak.cs b/src/Khd.Core.Domain/Models/BaseProductionOrderSplitBak.cs new file mode 100644 index 0000000..bf5b376 --- /dev/null +++ b/src/Khd.Core.Domain/Models/BaseProductionOrderSplitBak.cs @@ -0,0 +1,83 @@ + +//----------------------------------------------------------------------- +// +// * Copyright (C) 2021 KEHAIDASOFT All Rights Reserved +// * version : 4.0.30319.42000 +// * author : khd by t4-2 +// +//----------------------------------------------------------------------- + +using System; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; + +namespace Khd.Core.Domain.Models +{ + + [Table("base_production_order_split_bak")] + public class BaseProductionOrderSplitBak + { + + [Key] + [Column("id")] + public string id { get; set; } + + [Column("site_code")] + public string siteCode { get; set; } + + /// + /// 线体编码 + /// + [Column("line_code")] + public string lineCode { get; set; } + + /// + /// 线体名称 + /// + [Column("line_name")] + public string lineName { get; set; } + + /// + /// 订单号 + /// + [Column("order_code")] + public string orderCode { get; set; } + + /// + /// 产品编码 + /// + [Column("prod_code")] + public string prodCode { get; set; } + + /// + /// 产品名称 + /// + [Column("prod_desc")] + public string prodDesc { get; set; } + + /// + /// 订单生产顺序 + /// + [Column("production_sequence")] + public int? productionSequence { get; set; } + + /// + /// 订单是否完成0未完成1完成 + /// + [Column("IsOver")] + public int? isover { get; set; } + + /// + /// 计划开始时间 + /// + [Column("est")] + public DateTime? est { get; set; } + + /// + /// 计划数量 + /// + [Column("Quantity")] + public int? quantity { get; set; } + } +} + diff --git a/src/Khd.Core.Domain/Models/BaseProductionOrderSplitLine.cs b/src/Khd.Core.Domain/Models/BaseProductionOrderSplitLine.cs new file mode 100644 index 0000000..96c6687 --- /dev/null +++ b/src/Khd.Core.Domain/Models/BaseProductionOrderSplitLine.cs @@ -0,0 +1,209 @@ + +//----------------------------------------------------------------------- +// +// * Copyright (C) 2021 KEHAIDASOFT All Rights Reserved +// * version : 4.0.30319.42000 +// * author : khd by t4-2 +// +//----------------------------------------------------------------------- + +using System; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; + +namespace Khd.Core.Domain.Models +{ + + [Table("base_production_order_split_line")] + public class BaseProductionOrderSplitLine + { + + [Key] + [Column("id")] + public string id { get; set; } + + [Column("site_code")] + public string siteCode { get; set; } + + /// + /// 线体编码 + /// + [Column("line_code")] + public string lineCode { get; set; } + + /// + /// 线体名称 + /// + [Column("line_name")] + public string lineName { get; set; } + + /// + /// 订单号 + /// + [Column("order_code")] + public string orderCode { get; set; } + + /// + /// 产品编码 + /// + [Column("prod_code")] + public string prodCode { get; set; } + + /// + /// 产品名称 + /// + [Column("prod_desc")] + public string prodDesc { get; set; } + + /// + /// 计划开始时间 + /// + [Column("est")] + public DateTime? est { get; set; } + + /// + /// 计划数量 + /// + [Column("Quantity")] + public int? quantity { get; set; } + + /// + /// 可用计划数 + /// + [Column("available_quantity")] + public int? availableQuantity { get; set; } + + /// + /// 上线数量 + /// + [Column("online_quantity")] + public int? onlineQuantity { get; set; } + + /// + /// 下线数量 + /// + [Column("ActualQuantity")] + public int? actualquantity { get; set; } + + [Column("UpQuantity")] + public int? upquantity { get; set; } + + /// + /// 出库数量 + /// + [Column("OutWareHouseQuantity")] + public int? outwarehousequantity { get; set; } + + [Column("DownQuantity")] + public int? downquantity { get; set; } + + /// + /// 订单是否完成0未完成1完成 + /// + [Column("IsOver")] + public int? isover { get; set; } + + /// + /// 排产时间 + /// + [Column("scheduling_time")] + public DateTime? schedulingTime { get; set; } + + /// + /// 拆单状态:0正在拆单,1正常 + /// + [Column("split_status")] + public string splitStatus { get; set; } + + /// + /// 订单生产顺序 + /// + [Column("production_sequence")] + public int? productionSequence { get; set; } + + /// + /// 创建时间 + /// + [Column("create_date")] + public DateTime? createDate { get; set; } + + /// + /// 最后更新时间 + /// + [Column("last_update_date")] + public DateTime? lastUpdateDate { get; set; } + + /// + /// 创建人 + /// + [Column("create_by")] + public string createBy { get; set; } + + /// + /// 最后更新人 + /// + [Column("last_update_by")] + public string lastUpdateBy { get; set; } + + /// + /// 父订单id + /// + [Column("parent_order_id")] + public string parentOrderId { get; set; } + + /// + /// 0非源订单,1源订单 + /// + [Column("is_source")] + public string isSource { get; set; } + + /// + /// 0未同步,1已同步 + /// + [Column("is_sync")] + public string isSync { get; set; } + + /// + /// 0为未完成,1为已完成 + /// + [Column("is_completed")] + public string isCompleted { get; set; } + + /// + /// 企业编码 + /// + [Column("Enterprise_Code")] + public string enterpriseCode { get; set; } + + /// + /// 是否启用 + /// + [Column("Active")] + public string active { get; set; } + + /// + /// 工厂Id + /// + [Column("Site_Id")] + public string siteId { get; set; } + + /// + /// 企业Id + /// + [Column("Enterprise_Id")] + public string enterpriseId { get; set; } + + /// + /// 条码区间 + /// + [Column("min_max_barcode")] + public string minMaxBarcode { get; set; } + + /// + /// 订单审核状态(0:待审核,1:确认,2:拒绝,3:待作废) + /// + [Column("order_status")] + public int? orderStatus { get; set; } + } +} + diff --git a/src/Khd.Core.Domain/Models/BaseProductionOrderSplitReduct.cs b/src/Khd.Core.Domain/Models/BaseProductionOrderSplitReduct.cs new file mode 100644 index 0000000..404174a --- /dev/null +++ b/src/Khd.Core.Domain/Models/BaseProductionOrderSplitReduct.cs @@ -0,0 +1,203 @@ + +//----------------------------------------------------------------------- +// +// * Copyright (C) 2021 KEHAIDASOFT All Rights Reserved +// * version : 4.0.30319.42000 +// * author : khd by t4-2 +// +//----------------------------------------------------------------------- + +using System; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; + +namespace Khd.Core.Domain.Models +{ + + [Table("base_production_order_split_reduct")] + public class BaseProductionOrderSplitReduct + { + + [Key] + [Column("id")] + public string id { get; set; } + + [Column("site_code")] + public string siteCode { get; set; } + + /// + /// 线体编码 + /// + [Column("line_code")] + public string lineCode { get; set; } + + /// + /// 线体名称 + /// + [Column("line_name")] + public string lineName { get; set; } + + /// + /// 订单号 + /// + [Column("order_code")] + public string orderCode { get; set; } + + /// + /// 产品编码 + /// + [Column("prod_code")] + public string prodCode { get; set; } + + /// + /// 产品名称 + /// + [Column("prod_desc")] + public string prodDesc { get; set; } + + /// + /// 计划开始时间 + /// + [Column("est")] + public DateTime? est { get; set; } + + /// + /// 计划数量 + /// + [Column("Quantity")] + public int? quantity { get; set; } + + /// + /// 可用计划数 + /// + [Column("available_quantity")] + public int? availableQuantity { get; set; } + + /// + /// 上线数量 + /// + [Column("online_quantity")] + public int? onlineQuantity { get; set; } + + /// + /// 下线数量 + /// + [Column("ActualQuantity")] + public int? actualquantity { get; set; } + + [Column("UpQuantity")] + public int? upquantity { get; set; } + + /// + /// 出库数量 + /// + [Column("OutWareHouseQuantity")] + public int? outwarehousequantity { get; set; } + + [Column("DownQuantity")] + public int? downquantity { get; set; } + + /// + /// 订单是否完成0未完成1完成 + /// + [Column("IsOver")] + public int? isover { get; set; } + + /// + /// 排产时间 + /// + [Column("scheduling_time")] + public DateTime? schedulingTime { get; set; } + + /// + /// 拆单状态:0正在拆单,1正常 + /// + [Column("split_status")] + public string splitStatus { get; set; } + + /// + /// 订单生产顺序 + /// + [Column("production_sequence")] + public int? productionSequence { get; set; } + + /// + /// 创建时间 + /// + [Column("create_date")] + public DateTime? createDate { get; set; } + + /// + /// 最后更新时间 + /// + [Column("last_update_date")] + public DateTime? lastUpdateDate { get; set; } + + /// + /// 创建人 + /// + [Column("create_by")] + public string createBy { get; set; } + + /// + /// 最后更新人 + /// + [Column("last_update_by")] + public string lastUpdateBy { get; set; } + + /// + /// 父订单id + /// + [Column("parent_order_id")] + public string parentOrderId { get; set; } + + /// + /// 0非源订单,1源订单 + /// + [Column("is_source")] + public string isSource { get; set; } + + /// + /// 0未同步,1已同步 + /// + [Column("is_sync")] + public string isSync { get; set; } + + /// + /// 0为未完成,1为已完成 + /// + [Column("is_completed")] + public string isCompleted { get; set; } + + /// + /// 企业编码 + /// + [Column("Enterprise_Code")] + public string enterpriseCode { get; set; } + + /// + /// 是否启用 + /// + [Column("Active")] + public string active { get; set; } + + /// + /// 工厂Id + /// + [Column("Site_Id")] + public string siteId { get; set; } + + /// + /// 企业Id + /// + [Column("Enterprise_Id")] + public string enterpriseId { get; set; } + + /// + /// 条码区间 + /// + [Column("min_max_barcode")] + public string minMaxBarcode { get; set; } + } +} + diff --git a/src/Khd.Core.Domain/Models/BaseProductionOrderSplitTextinsert.cs b/src/Khd.Core.Domain/Models/BaseProductionOrderSplitTextinsert.cs new file mode 100644 index 0000000..57c4c36 --- /dev/null +++ b/src/Khd.Core.Domain/Models/BaseProductionOrderSplitTextinsert.cs @@ -0,0 +1,203 @@ + +//----------------------------------------------------------------------- +// +// * Copyright (C) 2021 KEHAIDASOFT All Rights Reserved +// * version : 4.0.30319.42000 +// * author : khd by t4-2 +// +//----------------------------------------------------------------------- + +using System; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; + +namespace Khd.Core.Domain.Models +{ + + [Table("base_production_order_split_textinsert")] + public class BaseProductionOrderSplitTextinsert + { + + [Key] + [Column("id")] + public string id { get; set; } + + [Column("site_code")] + public string siteCode { get; set; } + + /// + /// 线体编码 + /// + [Column("line_code")] + public string lineCode { get; set; } + + /// + /// 线体名称 + /// + [Column("line_name")] + public string lineName { get; set; } + + /// + /// 订单号 + /// + [Column("order_code")] + public string orderCode { get; set; } + + /// + /// 产品编码 + /// + [Column("prod_code")] + public string prodCode { get; set; } + + /// + /// 产品名称 + /// + [Column("prod_desc")] + public string prodDesc { get; set; } + + /// + /// 订单是否完成0未完成1完成 + /// + [Column("IsOver")] + public int? isover { get; set; } + + /// + /// 计划开始时间 + /// + [Column("est")] + public DateTime? est { get; set; } + + /// + /// 计划数量 + /// + [Column("Quantity")] + public int? quantity { get; set; } + + /// + /// 可用计划数 + /// + [Column("available_quantity")] + public int? availableQuantity { get; set; } + + /// + /// 上线数量 + /// + [Column("online_quantity")] + public int? onlineQuantity { get; set; } + + /// + /// 下线数量 + /// + [Column("ActualQuantity")] + public int? actualquantity { get; set; } + + [Column("UpQuantity")] + public int? upquantity { get; set; } + + /// + /// 出库数量 + /// + [Column("OutWareHouseQuantity")] + public int? outwarehousequantity { get; set; } + + [Column("DownQuantity")] + public int? downquantity { get; set; } + + /// + /// 排产时间 + /// + [Column("scheduling_time")] + public DateTime? schedulingTime { get; set; } + + /// + /// 拆单状态:0正在拆单,1正常 + /// + [Column("split_status")] + public string splitStatus { get; set; } + + /// + /// 订单生产顺序 + /// + [Column("production_sequence")] + public int? productionSequence { get; set; } + + /// + /// 创建时间 + /// + [Column("create_date")] + public DateTime? createDate { get; set; } + + /// + /// 最后更新时间 + /// + [Column("last_update_date")] + public DateTime? lastUpdateDate { get; set; } + + /// + /// 创建人 + /// + [Column("create_by")] + public string createBy { get; set; } + + /// + /// 最后更新人 + /// + [Column("last_update_by")] + public string lastUpdateBy { get; set; } + + /// + /// 父订单id + /// + [Column("parent_order_id")] + public string parentOrderId { get; set; } + + /// + /// 0非源订单,1源订单 + /// + [Column("is_source")] + public string isSource { get; set; } + + /// + /// 0未同步,1已同步 + /// + [Column("is_sync")] + public string isSync { get; set; } + + /// + /// 0为未完成,1为已完成 + /// + [Column("is_completed")] + public string isCompleted { get; set; } + + /// + /// 企业编码 + /// + [Column("Enterprise_Code")] + public string enterpriseCode { get; set; } + + /// + /// 是否启用 + /// + [Column("Active")] + public string active { get; set; } + + /// + /// 工厂Id + /// + [Column("Site_Id")] + public string siteId { get; set; } + + /// + /// 企业Id + /// + [Column("Enterprise_Id")] + public string enterpriseId { get; set; } + + /// + /// 条码区间 + /// + [Column("min_max_barcode")] + public string minMaxBarcode { get; set; } + } +} + diff --git a/src/Khd.Core.Domain/Models/BaseRejects.cs b/src/Khd.Core.Domain/Models/BaseRejects.cs new file mode 100644 index 0000000..b53b547 --- /dev/null +++ b/src/Khd.Core.Domain/Models/BaseRejects.cs @@ -0,0 +1,62 @@ + +//----------------------------------------------------------------------- +// +// * Copyright (C) 2021 KEHAIDASOFT All Rights Reserved +// * version : 4.0.30319.42000 +// * author : khd by t4-2 +// +//----------------------------------------------------------------------- + +using System; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; + +namespace Khd.Core.Domain.Models +{ + + [Table("base_rejects")] + public class BaseRejects + { + + [Key] + [Column("id")] + public Guid id { get; set; } + + [Column("car_no")] + public int? carNo { get; set; } + + [Column("site_node")] + public int? siteNode { get; set; } + + [Column("is_delete")] + public int? isDelete { get; set; } + + [Column("create_time")] + public DateTime? createTime { get; set; } + + [Column("create_id")] + public Guid? createId { get; set; } + + [Column("create_by")] + public string createBy { get; set; } + + [Column("modify_time")] + public DateTime? modifyTime { get; set; } + + [Column("modify_id")] + public Guid? modifyId { get; set; } + + [Column("modify_by")] + public string modifyBy { get; set; } + + [Column("definefield3")] + public string definefield3 { get; set; } + + [Column("definefield1")] + public string definefield1 { get; set; } + + [Column("definefield2")] + public string definefield2 { get; set; } + } +} + diff --git a/src/Khd.Core.Domain/Models/BaseSitearea.cs b/src/Khd.Core.Domain/Models/BaseSitearea.cs new file mode 100644 index 0000000..e3c14aa --- /dev/null +++ b/src/Khd.Core.Domain/Models/BaseSitearea.cs @@ -0,0 +1,98 @@ + +//----------------------------------------------------------------------- +// +// * Copyright (C) 2021 KEHAIDASOFT All Rights Reserved +// * version : 4.0.30319.42000 +// * author : khd by t4-2 +// +//----------------------------------------------------------------------- + +using System; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; + +namespace Khd.Core.Domain.Models +{ + + [Table("base_sitearea")] + public class BaseSitearea + { + + [Key] + [Column("id")] + public int id { get; set; } + + /// + /// 站台id + /// + [Column("site_id")] + public Guid? siteId { get; set; } + + /// + /// 站台编码 + /// + [Column("site_no")] + public string siteNo { get; set; } + + /// + /// 站台名称 + /// + [Column("site_name")] + public string siteName { get; set; } + + /// + /// 区域id + /// + [Column("area_id")] + public Guid? areaId { get; set; } + + /// + /// 区域编码 + /// + [Column("area_no")] + public string areaNo { get; set; } + + /// + /// 区域名称 + /// + [Column("area_name")] + public string areaName { get; set; } + + /// + /// 路径去向值 + /// + [Column("site_value")] + public string siteValue { get; set; } + + [Column("is_delete")] + public int? isDelete { get; set; } + + [Column("create_time")] + public DateTime? createTime { get; set; } + + [Column("create_id")] + public Guid? createId { get; set; } + + [Column("create_by")] + public string createBy { get; set; } + + [Column("modify_time")] + public DateTime? modifyTime { get; set; } + + [Column("modify_id")] + public Guid? modifyId { get; set; } + + [Column("modify_by")] + public string modifyBy { get; set; } + + [Column("definefield3")] + public string definefield3 { get; set; } + + [Column("definefield1")] + public string definefield1 { get; set; } + + [Column("definefield2")] + public string definefield2 { get; set; } + } +} + diff --git a/src/Khd.Core.Domain/Models/BaseSitenode.cs b/src/Khd.Core.Domain/Models/BaseSitenode.cs new file mode 100644 index 0000000..c46e99f --- /dev/null +++ b/src/Khd.Core.Domain/Models/BaseSitenode.cs @@ -0,0 +1,92 @@ + +//----------------------------------------------------------------------- +// +// * Copyright (C) 2021 KEHAIDASOFT All Rights Reserved +// * version : 4.0.30319.42000 +// * author : khd by t4-2 +// +//----------------------------------------------------------------------- + +using System; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; + +namespace Khd.Core.Domain.Models +{ + + [Table("base_sitenode")] + public class BaseSitenode + { + + [Key] + [Column("id")] + public Guid? id { get; set; } + + /// + /// 站台编码 + /// + [Column("site_no")] + public string siteNo { get; set; } + + /// + /// 站台名称 + /// + [Column("site_name")] + public string siteName { get; set; } + + /// + /// 站台类型 + /// + [Column("site_tasktype")] + public Guid? siteTasktype { get; set; } + + /// + /// ip地址 + /// + [Column("site_ipaddress")] + public string siteIpaddress { get; set; } + + /// + /// 链接服务器端口号 + /// + [Column("site_serverport")] + public int? siteServerport { get; set; } + + /// + /// thrift端口号 + /// + [Column("thrift_port")] + public int? thriftPort { get; set; } + + [Column("is_delete")] + public int? isDelete { get; set; } + + [Column("create_time")] + public DateTime? createTime { get; set; } + + [Column("create_id")] + public Guid? createId { get; set; } + + [Column("create_by")] + public string createBy { get; set; } + + [Column("modify_time")] + public DateTime? modifyTime { get; set; } + + [Column("modify_id")] + public Guid? modifyId { get; set; } + + [Column("modify_by")] + public string modifyBy { get; set; } + + [Column("definefield3")] + public string definefield3 { get; set; } + + [Column("definefield1")] + public string definefield1 { get; set; } + + [Column("definefield2")] + public string definefield2 { get; set; } + } +} + diff --git a/src/Khd.Core.Domain/Models/BaseSitenum.cs b/src/Khd.Core.Domain/Models/BaseSitenum.cs new file mode 100644 index 0000000..cb36516 --- /dev/null +++ b/src/Khd.Core.Domain/Models/BaseSitenum.cs @@ -0,0 +1,41 @@ + +//----------------------------------------------------------------------- +// +// * Copyright (C) 2021 KEHAIDASOFT All Rights Reserved +// * version : 4.0.30319.42000 +// * author : khd by t4-2 +// +//----------------------------------------------------------------------- + +using System; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; + +namespace Khd.Core.Domain.Models +{ + + [Table("base_sitenum")] + public class BaseSitenum + { + + [Key] + [Column("id")] + public Guid id { get; set; } + + [Column("sitenode_no")] + public int? sitenodeNo { get; set; } + + [Column("order_code")] + public string orderCode { get; set; } + + [Column("materiel_num")] + public int? materielNum { get; set; } + + [Column("car_no")] + public int? carNo { get; set; } + + [Column("create_time")] + public DateTime? createTime { get; set; } + } +} + diff --git a/src/Khd.Core.Domain/Models/BaseStandbytime.cs b/src/Khd.Core.Domain/Models/BaseStandbytime.cs new file mode 100644 index 0000000..c26b2cc --- /dev/null +++ b/src/Khd.Core.Domain/Models/BaseStandbytime.cs @@ -0,0 +1,50 @@ + +//----------------------------------------------------------------------- +// +// * Copyright (C) 2021 KEHAIDASOFT All Rights Reserved +// * version : 4.0.30319.42000 +// * author : khd by t4-2 +// +//----------------------------------------------------------------------- + +using System; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; + +namespace Khd.Core.Domain.Models +{ + + [Table("base_standbytime")] + public class BaseStandbytime + { + + [Key] + [Column("id")] + public Guid id { get; set; } + + /// + /// 线体 + /// + [Column("line")] + public int? line { get; set; } + + /// + /// 日期 + /// + [Column("ddate")] + public DateTime? ddate { get; set; } + + /// + /// 开始时间 + /// + [Column("begintime")] + public DateTime? begintime { get; set; } + + /// + /// 结束时间 + /// + [Column("endtime")] + public DateTime? endtime { get; set; } + } +} + diff --git a/src/Khd.Core.Domain/Models/BaseStorage.cs b/src/Khd.Core.Domain/Models/BaseStorage.cs new file mode 100644 index 0000000..d0721b3 --- /dev/null +++ b/src/Khd.Core.Domain/Models/BaseStorage.cs @@ -0,0 +1,68 @@ + +//----------------------------------------------------------------------- +// +// * Copyright (C) 2021 KEHAIDASOFT All Rights Reserved +// * version : 4.0.30319.42000 +// * author : khd by t4-2 +// +//----------------------------------------------------------------------- + +using System; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; + +namespace Khd.Core.Domain.Models +{ + + [Table("base_storage")] + public class BaseStorage + { + + [Key] + [Column("id")] + public Guid id { get; set; } + + /// + /// 区域编码 + /// + [Column("storage_no")] + public string storageNo { get; set; } + + /// + /// 区域名称 + /// + [Column("storage_name")] + public string storageName { get; set; } + + [Column("is_delete")] + public int? isDelete { get; set; } + + [Column("create_time")] + public DateTime? createTime { get; set; } + + [Column("create_id")] + public Guid? createId { get; set; } + + [Column("create_by")] + public string createBy { get; set; } + + [Column("modify_time")] + public DateTime? modifyTime { get; set; } + + [Column("modify_id")] + public Guid? modifyId { get; set; } + + [Column("modify_by")] + public string modifyBy { get; set; } + + [Column("definefield3")] + public string definefield3 { get; set; } + + [Column("definefield1")] + public string definefield1 { get; set; } + + [Column("definefield2")] + public string definefield2 { get; set; } + } +} + diff --git a/src/Khd.Core.Domain/Models/BaseSystemconfig.cs b/src/Khd.Core.Domain/Models/BaseSystemconfig.cs new file mode 100644 index 0000000..f725d48 --- /dev/null +++ b/src/Khd.Core.Domain/Models/BaseSystemconfig.cs @@ -0,0 +1,77 @@ + +//----------------------------------------------------------------------- +// +// * Copyright (C) 2021 KEHAIDASOFT All Rights Reserved +// * version : 4.0.30319.42000 +// * author : khd by t4-2 +// +//----------------------------------------------------------------------- + +using System; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; + +namespace Khd.Core.Domain.Models +{ + + [Table("base_systemconfig")] + public class BaseSystemconfig + { + + [Key] + [Column("id")] + public Guid id { get; set; } + + /// + /// 系统设置编码 + /// + [Column("system_filedno")] + public string systemFiledno { get; set; } + + /// + /// 系统配置值 + /// + [Column("system_filedval")] + public string systemFiledval { get; set; } + + /// + /// 字段描述 + /// + [Column("system_fileddesc")] + public string systemFileddesc { get; set; } + + [Column("is_delete")] + public int? isDelete { get; set; } + + [Column("create_time")] + public DateTime? createTime { get; set; } + + [Column("create_id")] + public Guid? createId { get; set; } + + [Column("create_by")] + public string createBy { get; set; } + + [Column("modify_time")] + public DateTime? modifyTime { get; set; } + + [Column("modify_id")] + public Guid? modifyId { get; set; } + + [Column("modify_by")] + public string modifyBy { get; set; } + + [Column("definefield3")] + public string definefield3 { get; set; } + + [Column("definefield1")] + public string definefield1 { get; set; } + + [Column("definefield2")] + public string definefield2 { get; set; } + + [Column("line_id")] + public Guid? lineId { get; set; } + } +} + diff --git a/src/Khd.Core.Domain/Models/BaseTasktstatus.cs b/src/Khd.Core.Domain/Models/BaseTasktstatus.cs new file mode 100644 index 0000000..a750dc9 --- /dev/null +++ b/src/Khd.Core.Domain/Models/BaseTasktstatus.cs @@ -0,0 +1,71 @@ + +//----------------------------------------------------------------------- +// +// * Copyright (C) 2021 KEHAIDASOFT All Rights Reserved +// * version : 4.0.30319.42000 +// * author : khd by t4-2 +// +//----------------------------------------------------------------------- + +using System; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; + +namespace Khd.Core.Domain.Models +{ + + [Table("base_tasktstatus")] + public class BaseTasktstatus + { + + [Key] + [Column("id")] + public Guid id { get; set; } + + /// + /// 任务状态编号 + /// + [Column("taskstatus_no")] + public string taskstatusNo { get; set; } + + /// + /// 任务状态名称 + /// + [Column("taskstatus_nm")] + public string taskstatusNm { get; set; } + + [Column("is_delete")] + public int? isDelete { get; set; } + + [Column("create_time")] + public DateTime? createTime { get; set; } + + [Column("create_id")] + public Guid? createId { get; set; } + + [Column("create_by")] + public string createBy { get; set; } + + [Column("modify_time")] + public DateTime? modifyTime { get; set; } + + [Column("modify_id")] + public Guid? modifyId { get; set; } + + [Column("modify_by")] + public string modifyBy { get; set; } + + [Column("definefield3")] + public string definefield3 { get; set; } + + [Column("definefield1")] + public string definefield1 { get; set; } + + [Column("definefield2")] + public string definefield2 { get; set; } + + [Column("line_id")] + public Guid? lineId { get; set; } + } +} + diff --git a/src/Khd.Core.Domain/Models/BaseTasktype.cs b/src/Khd.Core.Domain/Models/BaseTasktype.cs new file mode 100644 index 0000000..d097c7c --- /dev/null +++ b/src/Khd.Core.Domain/Models/BaseTasktype.cs @@ -0,0 +1,71 @@ + +//----------------------------------------------------------------------- +// +// * Copyright (C) 2021 KEHAIDASOFT All Rights Reserved +// * version : 4.0.30319.42000 +// * author : khd by t4-2 +// +//----------------------------------------------------------------------- + +using System; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; + +namespace Khd.Core.Domain.Models +{ + + [Table("base_tasktype")] + public class BaseTasktype + { + + [Key] + [Column("id")] + public Guid id { get; set; } + + /// + /// 任务类型编号 + /// + [Column("tasktype_no")] + public string tasktypeNo { get; set; } + + /// + /// 任务类型名称 + /// + [Column("tasktype_nm")] + public string tasktypeNm { get; set; } + + [Column("is_delete")] + public int? isDelete { get; set; } + + [Column("create_time")] + public DateTime? createTime { get; set; } + + [Column("create_id")] + public Guid? createId { get; set; } + + [Column("create_by")] + public string createBy { get; set; } + + [Column("modify_time")] + public DateTime? modifyTime { get; set; } + + [Column("modify_id")] + public Guid? modifyId { get; set; } + + [Column("modify_by")] + public string modifyBy { get; set; } + + [Column("definefield3")] + public string definefield3 { get; set; } + + [Column("definefield1")] + public string definefield1 { get; set; } + + [Column("definefield2")] + public string definefield2 { get; set; } + + [Column("line_id")] + public Guid? lineId { get; set; } + } +} + diff --git a/src/Khd.Core.Domain/Models/BaseUpdownnum.cs b/src/Khd.Core.Domain/Models/BaseUpdownnum.cs new file mode 100644 index 0000000..07d49c2 --- /dev/null +++ b/src/Khd.Core.Domain/Models/BaseUpdownnum.cs @@ -0,0 +1,80 @@ + +//----------------------------------------------------------------------- +// +// * Copyright (C) 2021 KEHAIDASOFT All Rights Reserved +// * version : 4.0.30319.42000 +// * author : khd by t4-2 +// +//----------------------------------------------------------------------- + +using System; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; + +namespace Khd.Core.Domain.Models +{ + + [Table("base_updownnum")] + public class BaseUpdownnum + { + + [Key] + [Column("id")] + public Guid id { get; set; } + + /// + /// 创建日期 + /// + [Column("create_date")] + public DateTime? createDate { get; set; } + + [Column("site_no")] + public int? siteNo { get; set; } + + [Column("materiel_no")] + public string materielNo { get; set; } + + /// + /// 上件数量 + /// + [Column("upnum")] + public int? upnum { get; set; } + + /// + /// 下件数量 + /// + [Column("downnum")] + public int? downnum { get; set; } + + [Column("is_delete")] + public int? isDelete { get; set; } + + [Column("create_time")] + public DateTime? createTime { get; set; } + + [Column("create_id")] + public Guid? createId { get; set; } + + [Column("create_by")] + public string createBy { get; set; } + + [Column("modify_time")] + public DateTime? modifyTime { get; set; } + + [Column("modify_id")] + public Guid? modifyId { get; set; } + + [Column("modify_by")] + public string modifyBy { get; set; } + + [Column("definefield3")] + public string definefield3 { get; set; } + + [Column("definefield1")] + public string definefield1 { get; set; } + + [Column("definefield2")] + public string definefield2 { get; set; } + } +} + diff --git a/src/Khd.Core.Domain/Models/BaseUpdownnumnew.cs b/src/Khd.Core.Domain/Models/BaseUpdownnumnew.cs new file mode 100644 index 0000000..bb42f36 --- /dev/null +++ b/src/Khd.Core.Domain/Models/BaseUpdownnumnew.cs @@ -0,0 +1,80 @@ + +//----------------------------------------------------------------------- +// +// * Copyright (C) 2021 KEHAIDASOFT All Rights Reserved +// * version : 4.0.30319.42000 +// * author : khd by t4-2 +// +//----------------------------------------------------------------------- + +using System; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; + +namespace Khd.Core.Domain.Models +{ + + [Table("base_updownnumnew")] + public class BaseUpdownnumnew + { + + [Key] + [Column("id")] + public Guid id { get; set; } + + /// + /// 创建日期 + /// + [Column("create_date")] + public DateTime? createDate { get; set; } + + [Column("site_no")] + public int? siteNo { get; set; } + + [Column("material_no")] + public string materialNo { get; set; } + + /// + /// 上件数量 + /// + [Column("upnum")] + public int? upnum { get; set; } + + /// + /// 下件数量 + /// + [Column("downnum")] + public int? downnum { get; set; } + + [Column("is_delete")] + public int? isDelete { get; set; } + + [Column("create_time")] + public DateTime? createTime { get; set; } + + [Column("create_id")] + public Guid? createId { get; set; } + + [Column("create_by")] + public string createBy { get; set; } + + [Column("modify_time")] + public DateTime? modifyTime { get; set; } + + [Column("modify_id")] + public Guid? modifyId { get; set; } + + [Column("modify_by")] + public string modifyBy { get; set; } + + [Column("definefield3")] + public string definefield3 { get; set; } + + [Column("definefield1")] + public string definefield1 { get; set; } + + [Column("definefield2")] + public string definefield2 { get; set; } + } +} + diff --git a/src/Khd.Core.Domain/Models/BaseWaitdownline.cs b/src/Khd.Core.Domain/Models/BaseWaitdownline.cs new file mode 100644 index 0000000..270575c --- /dev/null +++ b/src/Khd.Core.Domain/Models/BaseWaitdownline.cs @@ -0,0 +1,83 @@ + +//----------------------------------------------------------------------- +// +// * Copyright (C) 2021 KEHAIDASOFT All Rights Reserved +// * version : 4.0.30319.42000 +// * author : khd by t4-2 +// +//----------------------------------------------------------------------- + +using System; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; + +namespace Khd.Core.Domain.Models +{ + + [Table("base_waitdownline")] + public class BaseWaitdownline + { + + [Key] + [Column("id")] + public Guid? id { get; set; } + + /// + /// 小车id + /// + [Column("car_id")] + public Guid? carId { get; set; } + + /// + /// 小车编码 + /// + [Column("car_no")] + public int? carNo { get; set; } + + /// + /// 小车名称 + /// + [Column("car_name")] + public string carName { get; set; } + + [Column("downline")] + public int? downline { get; set; } + + [Column("is_delete")] + public int? isDelete { get; set; } + + [Column("create_time")] + public DateTime? createTime { get; set; } + + [Column("create_id")] + public Guid? createId { get; set; } + + [Column("create_by")] + public string createBy { get; set; } + + [Column("modify_time")] + public DateTime? modifyTime { get; set; } + + [Column("modify_id")] + public Guid? modifyId { get; set; } + + [Column("modify_by")] + public string modifyBy { get; set; } + + [Column("definefield3")] + public string definefield3 { get; set; } + + [Column("definefield1")] + public string definefield1 { get; set; } + + [Column("definefield2")] + public string definefield2 { get; set; } + + [Column("materiel_num")] + public int? materielNum { get; set; } + + [Column("materiel_no")] + public string materielNo { get; set; } + } +} + diff --git a/src/Khd.Core.Domain/Models/BasedataPowerclasslog.cs b/src/Khd.Core.Domain/Models/BasedataPowerclasslog.cs new file mode 100644 index 0000000..2dadccd --- /dev/null +++ b/src/Khd.Core.Domain/Models/BasedataPowerclasslog.cs @@ -0,0 +1,89 @@ + +//----------------------------------------------------------------------- +// +// * Copyright (C) 2021 KEHAIDASOFT All Rights Reserved +// * version : 4.0.30319.42000 +// * author : khd by t4-2 +// +//----------------------------------------------------------------------- + +using System; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; + +namespace Khd.Core.Domain.Models +{ + + [Table("basedata_powerclasslog")] + public class BasedataPowerclasslog + { + + [Key] + [Column("id")] + public int id { get; set; } + + /// + /// 当前耗电 + /// + [Column("frontElect")] + public string frontelect { get; set; } + + /// + /// 当前总耗电 + /// + [Column("totalElect")] + public string totalelect { get; set; } + + /// + /// 能耗 + /// + [Column("power")] + public string power { get; set; } + + [Column("createTime")] + public DateTime? createtime { get; set; } + + [Column("shiftName")] + public string shiftname { get; set; } + + [Column("lineId")] + public int? lineid { get; set; } + + /// + /// 1 副厂房电表 ,2 主厂房电表 + /// + [Column("powerType")] + public int? powertype { get; set; } + + [Column("is_delete")] + public int? isDelete { get; set; } + + [Column("create_time")] + public DateTime? createTime { get; set; } + + [Column("create_id")] + public Guid? createId { get; set; } + + [Column("create_by")] + public string createBy { get; set; } + + [Column("modify_time")] + public DateTime? modifyTime { get; set; } + + [Column("modify_id")] + public Guid? modifyId { get; set; } + + [Column("modify_by")] + public string modifyBy { get; set; } + + [Column("definefield3")] + public string definefield3 { get; set; } + + [Column("definefield1")] + public string definefield1 { get; set; } + + [Column("definefield2")] + public string definefield2 { get; set; } + } +} + diff --git a/src/Khd.Core.Domain/Models/BasedataUplinescancarlist.cs b/src/Khd.Core.Domain/Models/BasedataUplinescancarlist.cs new file mode 100644 index 0000000..ebb45ea --- /dev/null +++ b/src/Khd.Core.Domain/Models/BasedataUplinescancarlist.cs @@ -0,0 +1,95 @@ + +//----------------------------------------------------------------------- +// +// * Copyright (C) 2021 KEHAIDASOFT All Rights Reserved +// * version : 4.0.30319.42000 +// * author : khd by t4-2 +// +//----------------------------------------------------------------------- + +using System; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; + +namespace Khd.Core.Domain.Models +{ + + [Table("basedata_uplinescancarlist")] + public class BasedataUplinescancarlist + { + + [Key] + [Column("id")] + public int id { get; set; } + + /// + /// 任务订单号 + /// + [Column("MaterialNo")] + public string materialno { get; set; } + + /// + /// 任务号 + /// + [Column("carcode")] + public string carcode { get; set; } + + [Column("site_id")] + public Guid? siteId { get; set; } + + /// + /// 站台编号 + /// + [Column("SiteNo")] + public string siteno { get; set; } + + /// + /// 任务号 + /// + [Column("task_no")] + public Guid? taskNo { get; set; } + + /// + /// 完成状态 + /// + [Column("Number")] + public int? number { get; set; } + + /// + /// 单据状态 + /// + [Column("isover")] + public int? isover { get; set; } + + [Column("is_delete")] + public int? isDelete { get; set; } + + [Column("create_time")] + public DateTime? createTime { get; set; } + + [Column("create_id")] + public Guid? createId { get; set; } + + [Column("create_by")] + public string createBy { get; set; } + + [Column("modify_time")] + public DateTime? modifyTime { get; set; } + + [Column("modify_id")] + public Guid? modifyId { get; set; } + + [Column("modify_by")] + public string modifyBy { get; set; } + + [Column("definefield3")] + public string definefield3 { get; set; } + + [Column("definefield1")] + public string definefield1 { get; set; } + + [Column("definefield2")] + public string definefield2 { get; set; } + } +} + diff --git a/src/Khd.Core.Domain/Models/BusinessCarrierCargocage.cs b/src/Khd.Core.Domain/Models/BusinessCarrierCargocage.cs new file mode 100644 index 0000000..9cd513d --- /dev/null +++ b/src/Khd.Core.Domain/Models/BusinessCarrierCargocage.cs @@ -0,0 +1,92 @@ + +//----------------------------------------------------------------------- +// +// * Copyright (C) 2021 KEHAIDASOFT All Rights Reserved +// * version : 4.0.30319.42000 +// * author : khd by t4-2 +// +//----------------------------------------------------------------------- + +using System; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; + +namespace Khd.Core.Domain.Models +{ + + [Table("business_carrier_cargocage")] + public class BusinessCarrierCargocage + { + + [Key] + [Column("id")] + public int id { get; set; } + + /// + /// 小车id + /// + [Column("carrier_id")] + public Guid? carrierId { get; set; } + + /// + /// 小车编号 + /// + [Column("carrier_no")] + public string carrierNo { get; set; } + + /// + /// 托盘id + /// + [Column("cargocage_id")] + public Guid? cargocageId { get; set; } + + /// + /// 站台分流区 + /// + [Column("sitearea_id")] + public int? siteareaId { get; set; } + + /// + /// 指令id + /// + [Column("task_id")] + public int? taskId { get; set; } + + /// + /// 刷新站点时间 + /// + [Column("operate_time")] + public DateTime? operateTime { get; set; } + + [Column("is_delete")] + public int? isDelete { get; set; } + + [Column("create_time")] + public DateTime? createTime { get; set; } + + [Column("create_id")] + public Guid? createId { get; set; } + + [Column("create_by")] + public string createBy { get; set; } + + [Column("modify_time")] + public DateTime? modifyTime { get; set; } + + [Column("modify_id")] + public Guid? modifyId { get; set; } + + [Column("modify_by")] + public string modifyBy { get; set; } + + [Column("definefield3")] + public string definefield3 { get; set; } + + [Column("definefield1")] + public string definefield1 { get; set; } + + [Column("definefield2")] + public string definefield2 { get; set; } + } +} + diff --git a/src/Khd.Core.Domain/Models/BusinessCommand.cs b/src/Khd.Core.Domain/Models/BusinessCommand.cs new file mode 100644 index 0000000..5b82de0 --- /dev/null +++ b/src/Khd.Core.Domain/Models/BusinessCommand.cs @@ -0,0 +1,89 @@ + +//----------------------------------------------------------------------- +// +// * Copyright (C) 2021 KEHAIDASOFT All Rights Reserved +// * version : 4.0.30319.42000 +// * author : khd by t4-2 +// +//----------------------------------------------------------------------- + +using System; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; + +namespace Khd.Core.Domain.Models +{ + + [Table("business_command")] + public class BusinessCommand + { + + [Key] + [Column("id")] + public int id { get; set; } + + /// + /// 指令编码 + /// + [Column("command_no")] + public string commandNo { get; set; } + + /// + /// 指令类型 + /// + [Column("command_type")] + public int? commandType { get; set; } + + /// + /// 开始站台 + /// + [Column("start_site_id")] + public Guid? startSiteId { get; set; } + + /// + /// 下个站台 + /// + [Column("next_site_id")] + public Guid? nextSiteId { get; set; } + + /// + /// 操作时间 + /// + [Column("optdate")] + public DateTime? optdate { get; set; } + + [Column("is_delete")] + public int? isDelete { get; set; } + + [Column("create_time")] + public DateTime? createTime { get; set; } + + [Column("create_id")] + public Guid? createId { get; set; } + + [Column("create_by")] + public string createBy { get; set; } + + [Column("modify_time")] + public DateTime? modifyTime { get; set; } + + [Column("modify_id")] + public Guid? modifyId { get; set; } + + [Column("modify_by")] + public string modifyBy { get; set; } + + [Column("definefield3")] + public string definefield3 { get; set; } + + [Column("definefield1")] + public string definefield1 { get; set; } + + [Column("definefield2")] + public string definefield2 { get; set; } + + [Column("line_id")] + public Guid? lineId { get; set; } + } +} + diff --git a/src/Khd.Core.Domain/Models/BusinessOperationlog.cs b/src/Khd.Core.Domain/Models/BusinessOperationlog.cs new file mode 100644 index 0000000..b6300ba --- /dev/null +++ b/src/Khd.Core.Domain/Models/BusinessOperationlog.cs @@ -0,0 +1,68 @@ + +//----------------------------------------------------------------------- +// +// * Copyright (C) 2021 KEHAIDASOFT All Rights Reserved +// * version : 4.0.30319.42000 +// * author : khd by t4-2 +// +//----------------------------------------------------------------------- + +using System; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; + +namespace Khd.Core.Domain.Models +{ + + [Table("business_operationlog")] + public class BusinessOperationlog + { + + [Key] + [Column("id")] + public int id { get; set; } + + /// + /// 操作日志标题 + /// + [Column("opterate_title")] + public string opterateTitle { get; set; } + + /// + /// 操作日志内容 + /// + [Column("opterate_desc")] + public string opterateDesc { get; set; } + + [Column("is_delete")] + public int? isDelete { get; set; } + + [Column("create_time")] + public DateTime? createTime { get; set; } + + [Column("create_id")] + public Guid? createId { get; set; } + + [Column("create_by")] + public string createBy { get; set; } + + [Column("modify_time")] + public DateTime? modifyTime { get; set; } + + [Column("modify_id")] + public Guid? modifyId { get; set; } + + [Column("modify_by")] + public string modifyBy { get; set; } + + [Column("definefield3")] + public string definefield3 { get; set; } + + [Column("definefield1")] + public string definefield1 { get; set; } + + [Column("definefield2")] + public string definefield2 { get; set; } + } +} + diff --git a/src/Khd.Core.Domain/Models/BusinessSitehistory.cs b/src/Khd.Core.Domain/Models/BusinessSitehistory.cs new file mode 100644 index 0000000..55e8122 --- /dev/null +++ b/src/Khd.Core.Domain/Models/BusinessSitehistory.cs @@ -0,0 +1,92 @@ + +//----------------------------------------------------------------------- +// +// * Copyright (C) 2021 KEHAIDASOFT All Rights Reserved +// * version : 4.0.30319.42000 +// * author : khd by t4-2 +// +//----------------------------------------------------------------------- + +using System; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; + +namespace Khd.Core.Domain.Models +{ + + [Table("business_sitehistory")] + public class BusinessSitehistory + { + + [Key] + [Column("id")] + public int id { get; set; } + + /// + /// 站台 + /// + [Column("site_id")] + public Guid? siteId { get; set; } + + /// + /// 载具 + /// + [Column("car_id")] + public Guid? carId { get; set; } + + /// + /// 任务 + /// + [Column("task_id")] + public Guid? taskId { get; set; } + + /// + /// 路径值 + /// + [Column("sitearea_val")] + public string siteareaVal { get; set; } + + /// + /// 指令 + /// + [Column("command_id")] + public Guid? commandId { get; set; } + + /// + /// 操作时间 + /// + [Column("operate_time")] + public DateTime? operateTime { get; set; } + + [Column("is_delete")] + public int? isDelete { get; set; } + + [Column("create_time")] + public DateTime? createTime { get; set; } + + [Column("create_id")] + public Guid? createId { get; set; } + + [Column("create_by")] + public string createBy { get; set; } + + [Column("modify_time")] + public DateTime? modifyTime { get; set; } + + [Column("modify_id")] + public Guid? modifyId { get; set; } + + [Column("modify_by")] + public string modifyBy { get; set; } + + [Column("definefield3")] + public string definefield3 { get; set; } + + [Column("definefield1")] + public string definefield1 { get; set; } + + [Column("definefield2")] + public string definefield2 { get; set; } + } +} + diff --git a/src/Khd.Core.Domain/Models/BusinessTask.cs b/src/Khd.Core.Domain/Models/BusinessTask.cs new file mode 100644 index 0000000..c990129 --- /dev/null +++ b/src/Khd.Core.Domain/Models/BusinessTask.cs @@ -0,0 +1,116 @@ + +//----------------------------------------------------------------------- +// +// * Copyright (C) 2021 KEHAIDASOFT All Rights Reserved +// * version : 4.0.30319.42000 +// * author : khd by t4-2 +// +//----------------------------------------------------------------------- + +using System; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; + +namespace Khd.Core.Domain.Models +{ + + [Table("business_task")] + public class BusinessTask + { + + [Key] + [Column("id")] + public int id { get; set; } + + /// + /// 任务订单号 + /// + [Column("order_no")] + public string orderNo { get; set; } + + /// + /// 任务号 + /// + [Column("task_no")] + public Guid? taskNo { get; set; } + + /// + /// 预设线路 + /// + [Column("pre_line_id")] + public Guid? preLineId { get; set; } + + /// + /// 预设线名称 + /// + [Column("pre_line_name")] + public string preLineName { get; set; } + + /// + /// 完成状态 + /// + [Column("complete_state")] + public int? completeState { get; set; } + + /// + /// 单据状态 + /// + [Column("task_state")] + public Guid? taskState { get; set; } + + /// + /// 任务类型 + /// + [Column("task_type")] + public Guid? taskType { get; set; } + + /// + /// 任务出发站台 + /// + [Column("site_id")] + public Guid? siteId { get; set; } + + /// + /// 目标站台分流区 + /// + [Column("sitearea_id")] + public int? siteareaId { get; set; } + + /// + /// 操作时间 + /// + [Column("optdate")] + public DateTime? optdate { get; set; } + + [Column("is_delete")] + public int? isDelete { get; set; } + + [Column("create_time")] + public DateTime? createTime { get; set; } + + [Column("create_id")] + public Guid? createId { get; set; } + + [Column("create_by")] + public string createBy { get; set; } + + [Column("modify_time")] + public DateTime? modifyTime { get; set; } + + [Column("modify_id")] + public Guid? modifyId { get; set; } + + [Column("modify_by")] + public string modifyBy { get; set; } + + [Column("definefield3")] + public string definefield3 { get; set; } + + [Column("definefield1")] + public string definefield1 { get; set; } + + [Column("definefield2")] + public string definefield2 { get; set; } + } +} + diff --git a/src/Khd.Core.Domain/Models/DataCargocageMaterialdetail.cs b/src/Khd.Core.Domain/Models/DataCargocageMaterialdetail.cs new file mode 100644 index 0000000..2f45262 --- /dev/null +++ b/src/Khd.Core.Domain/Models/DataCargocageMaterialdetail.cs @@ -0,0 +1,77 @@ + +//----------------------------------------------------------------------- +// +// * Copyright (C) 2021 KEHAIDASOFT All Rights Reserved +// * version : 4.0.30319.42000 +// * author : khd by t4-2 +// +//----------------------------------------------------------------------- + +using System; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; + +namespace Khd.Core.Domain.Models +{ + + [Table("data_cargocage_materialdetail")] + public class DataCargocageMaterialdetail + { + + [Key] + [Column("id")] + public int id { get; set; } + + /// + /// 托盘id + /// + [Column("cargocage_id")] + public Guid? cargocageId { get; set; } + + /// + /// 物料编码 + /// + [Column("material_no")] + public string materialNo { get; set; } + + [Column("material_barcode")] + public string materialBarcode { get; set; } + + /// + /// 数量 + /// + [Column("material_amount")] + public int? materialAmount { get; set; } + + [Column("is_delete")] + public int? isDelete { get; set; } + + [Column("create_time")] + public DateTime? createTime { get; set; } + + [Column("create_id")] + public Guid? createId { get; set; } + + [Column("create_by")] + public string createBy { get; set; } + + [Column("modify_time")] + public DateTime? modifyTime { get; set; } + + [Column("modify_id")] + public Guid? modifyId { get; set; } + + [Column("modify_by")] + public string modifyBy { get; set; } + + [Column("definefield3")] + public string definefield3 { get; set; } + + [Column("definefield1")] + public string definefield1 { get; set; } + + [Column("definefield2")] + public string definefield2 { get; set; } + } +} + diff --git a/src/Khd.Core.Domain/Models/DataCargocageProduct.cs b/src/Khd.Core.Domain/Models/DataCargocageProduct.cs new file mode 100644 index 0000000..2c55c65 --- /dev/null +++ b/src/Khd.Core.Domain/Models/DataCargocageProduct.cs @@ -0,0 +1,86 @@ + +//----------------------------------------------------------------------- +// +// * Copyright (C) 2021 KEHAIDASOFT All Rights Reserved +// * version : 4.0.30319.42000 +// * author : khd by t4-2 +// +//----------------------------------------------------------------------- + +using System; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; + +namespace Khd.Core.Domain.Models +{ + + [Table("data_cargocage_product")] + public class DataCargocageProduct + { + + [Key] + [Column("id")] + public int id { get; set; } + + /// + /// 托盘id + /// + [Column("cargocage_id")] + public Guid? cargocageId { get; set; } + + /// + /// 物料描述 + /// + [Column("material_desc")] + public string materialDesc { get; set; } + + /// + /// 物料编码 + /// + [Column("material_no")] + public string materialNo { get; set; } + + /// + /// boomid + /// + [Column("boom_id")] + public Guid? boomId { get; set; } + + /// + /// 数量 + /// + [Column("material_amount")] + public int? materialAmount { get; set; } + + [Column("is_delete")] + public int? isDelete { get; set; } + + [Column("create_time")] + public DateTime? createTime { get; set; } + + [Column("create_id")] + public Guid? createId { get; set; } + + [Column("create_by")] + public string createBy { get; set; } + + [Column("modify_time")] + public DateTime? modifyTime { get; set; } + + [Column("modify_id")] + public Guid? modifyId { get; set; } + + [Column("modify_by")] + public string modifyBy { get; set; } + + [Column("definefield3")] + public string definefield3 { get; set; } + + [Column("definefield1")] + public string definefield1 { get; set; } + + [Column("definefield2")] + public string definefield2 { get; set; } + } +} + diff --git a/src/Khd.Core.Domain/Models/Discretealarms.cs b/src/Khd.Core.Domain/Models/Discretealarms.cs new file mode 100644 index 0000000..3cb13fb --- /dev/null +++ b/src/Khd.Core.Domain/Models/Discretealarms.cs @@ -0,0 +1,47 @@ + +//----------------------------------------------------------------------- +// +// * Copyright (C) 2021 KEHAIDASOFT All Rights Reserved +// * version : 4.0.30319.42000 +// * author : khd by t4-2 +// +//----------------------------------------------------------------------- + +using System; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; + +namespace Khd.Core.Domain.Models +{ + + [Table("discretealarms")] + public class Discretealarms + { + + [Key] + [Column("ID")] + public Guid id { get; set; } + + [Column("Alarmtext")] + public string alarmtext { get; set; } + + [Column("FieldInfo")] + public string fieldinfo { get; set; } + + [Column("Triggertag")] + public string triggertag { get; set; } + + [Column("Triggerbit")] + public string triggerbit { get; set; } + + [Column("plc_value")] + public string plcValue { get; set; } + + /// + /// 创建时间 + /// + [Column("create_time")] + public DateTime? createTime { get; set; } + } +} + diff --git a/src/Khd.Core.Domain/Models/DmsBaseAlarmRule.cs b/src/Khd.Core.Domain/Models/DmsBaseAlarmRule.cs new file mode 100644 index 0000000..4f43b6a --- /dev/null +++ b/src/Khd.Core.Domain/Models/DmsBaseAlarmRule.cs @@ -0,0 +1,45 @@ +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; + +namespace Khd.Core.Domain.Models +{ + [Table("dms_base_alarm_rule")] + public class DmsBaseAlarmRule + { + [Key] + [Column("alarm_rule_id")] + public long AlarmRuleId { get; set; } + + [Column("device_id")] + public long DeviceId { get; set; } + + [Column("alarm_type")] + public string AlarmType { get; set; } + + [Column("alarm_level")] + public string AlarmLevel { get; set; } + + [Column("notice_type")] + public string NoticeType { get; set; } + + [Column("recover_type")] + public string RecoverType { get; set; } + + [Column("continue_time")] + public long ContinueTime { get; set; } + + [Column("alarm_reason")] + public string AlarmReason { get; set; } + + [Column("handle_suggest")] + public string HandleSuggest { get; set; } + + [Column("remark")] + public string Remark { get; set; } + [Column("alarm_status_word")] + public string StatusWord { get; set; } + + [Column("alarm_status")] + public int? Status { get; set; } + } +} diff --git a/src/Khd.Core.Domain/Models/DmsBaseDeviceLedger.cs b/src/Khd.Core.Domain/Models/DmsBaseDeviceLedger.cs new file mode 100644 index 0000000..6ceefb8 --- /dev/null +++ b/src/Khd.Core.Domain/Models/DmsBaseDeviceLedger.cs @@ -0,0 +1,46 @@ +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; + +namespace Khd.Core.Domain.Models +{ + [Table("dms_base_device_ledger")] + public class DmsBaseDeviceLedger + { + [Key] + [Column("device_id")] + public long DeviceId { get; set; } + + [Column("device_code")] + public string DeviceCode { get; set; } + + [Column("device_name")] + public string DeviceName { get; set; } + + [Column("station_id")] + public string StationId { get; set; } + + [Column("asset_number")] + public string AssetNumber { get; set; } + + [Column("device_location")] + public string DeviceLocation { get; set; } + + [Column("device_type_id")] + public string DeviceTypeId { get; set; } + + [Column("device_spec")] + public string DeviceSpec { get; set; } + + [Column("supplier_id")] + public string SupplierId { get; set; } + + [Column("device_status")] + public string DeviceStatus { get; set; } + + [Column("is_flag")] + public int IsFlag { get; set; } + + [Column("remark")] + public string Remark { get; set; } + } +} diff --git a/src/Khd.Core.Domain/Models/DmsRecordAlarmInfo.cs b/src/Khd.Core.Domain/Models/DmsRecordAlarmInfo.cs new file mode 100644 index 0000000..5f231c5 --- /dev/null +++ b/src/Khd.Core.Domain/Models/DmsRecordAlarmInfo.cs @@ -0,0 +1,68 @@ +using System; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; + +namespace Khd.Core.Domain.Models +{ + [Table("dms_record_alarm_info")] + public class DmsRecordAlarmInfo + { + [Key] + [Column("alarm_id")] + public long AlarmId { get; set; } + + [Column("device_id")] + public long DeviceId { get; set; } + + [Column("alarm_rule_id")] + public long AlarmRuleId { get; set; } + + [Column("alarm_begin_time")] + public DateTime AlarmBeginTime { get; set; } + + [Column("alarm_end_time")] + public DateTime AlarmEndTime { get; set; } + + [Column("continue_time")] + public long ContinueTime { get; set; } + + [Column("alarm_reason")] + public string AlarmReason { get; set; } + + [Column("alarm_data")] + public string AlarmData { get; set; } + + [Column("alarm_status")] + public string AlarmStatus { get; set; } + + [Column("handle_suggest")] + public string HandleSuggest { get; set; } + + [Column("notice_status")] + public string NoticeStatus { get; set; } + + [Column("handle_user")] + public string HandleUser { get; set; } + + [Column("handle_time")] + public DateTime? HandleTime { get; set; } + + [Column("cause_analysis")] + public string CauseAnalysis { get; set; } + + [Column("remark")] + public string Remark { get; set; } + + [Column("create_by")] + public string CreateBy { get; set; } + + [Column("create_time")] + public DateTime CreateTime { get; set; } + + [Column("update_by")] + public string UpdateBy { get; set; } + + [Column("update_time")] + public DateTime? UpdateTime { get; set; } + } +} diff --git a/src/Khd.Core.Domain/Models/DmsRecordAlarmTime.cs b/src/Khd.Core.Domain/Models/DmsRecordAlarmTime.cs new file mode 100644 index 0000000..ed58954 --- /dev/null +++ b/src/Khd.Core.Domain/Models/DmsRecordAlarmTime.cs @@ -0,0 +1,50 @@ +using System; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; + +namespace Khd.Core.Domain.Models +{ + [Table("dms_record_alarm_time")] + public class DmsRecordAlarmTime + { + [Key] + [Column("alarm_id")] + public long AlarmId { get; set; } + + [Column("device_id")] + public long DeviceId { get; set; } + + [Column("alarm_rule_id")] + public long AlarmRuleId { get; set; } + + [Column("alarm_begin_time")] + public DateTime AlarmBeginTime { get; set; } + + [Column("continue_time")] + public long ContinueTime { get; set; } + + [Column("alarm_reason")] + public string AlarmReason { get; set; } + + [Column("alarm_data")] + public string AlarmData { get; set; } + + [Column("handle_suggest")] + public string HandleSuggest { get; set; } + + [Column("remark")] + public string Remark { get; set; } + + [Column("create_by")] + public string CreateBy { get; set; } + + [Column("create_time")] + public DateTime CreateTime { get; set; } + + [Column("update_by")] + public string UpdateBy { get; set; } + + [Column("update_time")] + public DateTime UpdateTime { get; set; } + } +} diff --git a/src/Khd.Core.Domain/Models/MesBaseBarcodeInfo.cs b/src/Khd.Core.Domain/Models/MesBaseBarcodeInfo.cs new file mode 100644 index 0000000..f6d57b9 --- /dev/null +++ b/src/Khd.Core.Domain/Models/MesBaseBarcodeInfo.cs @@ -0,0 +1,212 @@ + +//----------------------------------------------------------------------- +// +// * Copyright (C) 2021 KEHAIDASOFT All Rights Reserved +// * version : 4.0.30319.42000 +// * author : khd by t4-2 +// +//----------------------------------------------------------------------- + +using System; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; + +namespace Khd.Core.Domain.Models +{ + + [Table("mes_base_barcode_info")] + public class MesBaseBarcodeInfo + { + [Column("complete_flag")] + public string completeFlag { get; set; } + [Column("purchase_order_id")] + public int? PurchaseOrderId { get; set; } + [Key] + [Column("barcode_id")] + public long barcodeId { get; set; } + + /// + /// 打印时间 + /// + [Column("print_time")] + public DateTime? printTime { get; set; } + + /// + /// 打印人 + /// + [Column("print_person")] + public string printPerson { get; set; } + + /// + /// 打印标识(0否1是) + /// + [Column("print_flag")] + public string printFlag { get; set; } + + /// + /// 批次标识(0否,1是);在打印时,如果物料已设置,则根据物料的批次信息,如果没有设置则在此需要选择,选择物料等信息保存后同步设置物料信息。 + /// + [Column("batch_flag")] + public string batchFlag { get; set; } + + /// + /// 条码类型(1原材料,2半成品,3成品,4背板) + /// + [Column("barcode_type")] + public string barcodeType { get; set; } + + /// + /// 条码内容;如果是按单个物料贴,则一个物料一个条码,如果是按批次贴,则条码跟批次代码相同 + /// + [Column("barcode_info")] + public string barcodeInfo { get; set; } + + /// + /// 批次代码 + /// + [Column("batch_code")] + public string batchCode { get; set; } + + /// + /// 托盘RFID代码 + /// + [Column("pallet_info_code")] + public string palletInfoCode { get; set; } + + /// + /// 物料ID,关联mes_base_material_info的material_id + /// + [Column("material_id")] + public long? materialId { get; set; } + + /// + /// 供应商ID + /// + [Column("manufacturer_id")] + public long? manufacturerId { get; set; } + + /// + /// 数量;如果是批次需要输入此字段 + /// + [Column("amount")] + public decimal? amount { get; set; } + + /// + /// 打印数量 + /// + [Column("print_number")] + public int? printNumber { get; set; } + + /// + /// 打印机台名称,打印时获取 + /// + [Column("machine_name")] + public string machineName { get; set; } + + /// + /// 采购订单号;适合原材料入库时 + /// + [Column("po_no")] + public string poNo { get; set; } + + /// + /// 生产日期;打印时根据领料单选择输入 + /// + [Column("production_date")] + public DateTime? productionDate { get; set; } + + /// + /// 接受日期;打印时的系统日期 + /// + [Column("accepted_date")] + public DateTime? acceptedDate { get; set; } + + /// + /// 最晚出库日期;可以直接输入,也可以根据日限计算 + /// + [Column("last_outstock_date")] + public DateTime? lastOutstockDate { get; set; } + + /// + /// 生产计划编号,关联mes_pd_product_plan的plan_code;适合生产出入库等 + /// + [Column("plan_code")] + public string planCode { get; set; } + + /// + /// 生产计划明细编号,关联mes_product_plan_detail的plan_detail_code;适合生产出入库等 + /// + [Column("plan_detail_code")] + public string planDetailCode { get; set; } + + /// + /// 销售订单ID + /// + [Column("sale_order_id")] + public long? saleOrderId { get; set; } + + /// + /// 销售订单编号;适合生产出入库等 + /// + [Column("saleorder_code")] + public string saleorderCode { get; set; } + + /// + /// 项目号 + /// + [Column("project_no")] + public string projectNo { get; set; } + + /// + /// 流水号 + /// + [Column("serial_number")] + public string serialNumber { get; set; } + + /// + /// 备注 + /// + [Column("remark")] + public string remark { get; set; } + + /// + /// 绑定状态(1绑定,0解绑) + /// + [Column("bind_status")] + public string bindStatus { get; set; } + + /// + /// 绑定托盘的人 + /// + [Column("bind_by")] + public string bindBy { get; set; } + + /// + /// 绑定托盘时间 + /// + [Column("bind_time")] + public DateTime? bindTime { get; set; } + + /// + /// 更新人 + /// + [Column("update_by")] + public string updateBy { get; set; } + + /// + /// 更新时间 + /// + [Column("update_time")] + public DateTime? updateTime { get; set; } + + /// + /// 绑定的物料条码(用来拆分绑定使用) + /// + [Column("bind_barcode")] + public string bindBarcode { get; set; } + + [Column("safe_flag")] + public string safeFlag { get; set; } + } +} + diff --git a/src/Khd.Core.Domain/Models/MesBaseMaterialInfo.cs b/src/Khd.Core.Domain/Models/MesBaseMaterialInfo.cs new file mode 100644 index 0000000..960e92b --- /dev/null +++ b/src/Khd.Core.Domain/Models/MesBaseMaterialInfo.cs @@ -0,0 +1,74 @@ +using System; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; + +namespace Khd.Core.Domain.Models +{ + [Table("mes_base_material_info")] + public class MesBaseMaterialInfo + { + [Key] + [Column("material_id")] + public long? MaterialId { get; set; } + [Column("erp_id")] + public long? ErpId { get; set; } + [Column("material_code")] + public string MaterialCode { get; set; } + [Column("old_material_code")] + public string OldMaterialCode { get; set; } + [Column("material_name")] + public string MaterialName { get; set; } + [Column("material_categories")] + public string MaterialCategories { get; set; } + [Column("material_subclass")] + public string MaterialSubclass { get; set; } + [Column("material_type_id")] + public int? MaterialTypeId { get; set; } + [Column("batch_flag")] + public string BatchFlag { get; set; } + [Column("batch_amount")] + public decimal? BatchAmount { get; set; } + [Column("material_unit_id")] + public long? MaterialUnitId { get; set; } + [Column("material_unit")] + public string MaterialUnit { get; set; } + [Column("material_matkl")] + public string MaterialMatkl { get; set; } + [Column("material_spec")] + public string MaterialSpec { get; set; } + [Column("net_weight")] + public decimal? NetWeight { get; set; } + [Column("gross_weight")] + public decimal? GrossWeight { get; set; } + //[Column("bind_flag")] + //public string BindFlag { get; set; } + [Column("factory_id")] + public int? FactoryId { get; set; } + [Column("create_org_id")] + public long? CreateOrgId { get; set; } + [Column("use_org_id")] + public long? UseOrgId { get; set; } + [Column("prodline_id")] + public int? ProdlineId { get; set; } + [Column("active_flag")] + public string ActiveFlag { get; set; } + [Column("deleted_flag")] + public string DeletedFlag { get; set; } + [Column("remark")] + public string Remark { get; set; } + [Column("purchase_price_unit_id")] + public long? PurchasePriceUnitId { get; set; } + [Column("create_by")] + public string CreateBy { get; set; } + [Column("create_time")] + public DateTime? CreateTime { get; set; } + [Column("update_by")] + public string UpdateBy { get; set; } + [Column("update_time")] + public DateTime? UpdateTime { get; set; } + [Column("approve_date")] + public DateTime? ApproveDate { get; set; } + [Column("erp_modify_date")] + public DateTime? ErpModifyDate { get; set; } + } +} diff --git a/src/Khd.Core.Domain/Models/MesBasePalletInfo.cs b/src/Khd.Core.Domain/Models/MesBasePalletInfo.cs new file mode 100644 index 0000000..801c75b --- /dev/null +++ b/src/Khd.Core.Domain/Models/MesBasePalletInfo.cs @@ -0,0 +1,92 @@ + +//----------------------------------------------------------------------- +// +// * Copyright (C) 2021 KEHAIDASOFT All Rights Reserved +// * version : 4.0.30319.42000 +// * author : khd by t4-2 +// +//----------------------------------------------------------------------- + +using System; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; + +namespace Khd.Core.Domain.Models +{ + + [Table("mes_base_pallet_info")] + public class MesBasePalletInfo + { + + [Key] + [Column("pallet_info_id")] + public int palletInfoId { get; set; } + + /// + /// 托盘信息RFID编码,不能修改 + /// + [Column("pallet_info_code")] + public string palletInfoCode { get; set; } + + /// + /// 物料ID,关联物料信息主键 + /// + [Column("material_id")] + public long? materialId { get; set; } + + /// + /// 物料编号 + /// + [Column("material_code")] + public string materialCode { get; set; } + + /// + /// 物料名称 + /// + [Column("material_name")] + public string materialName { get; set; } + + /// + /// 物料条码 + /// + [Column("material_barcode")] + public string materialBarcode { get; set; } + + /// + /// 备注 + /// + [Column("remark")] + public string remark { get; set; } + + /// + /// 创建人 + /// + [Column("create_by")] + public string createBy { get; set; } + + /// + /// 创建时间 + /// + [Column("create_time")] + public DateTime? createTime { get; set; } + + /// + /// 更新人 + /// + [Column("update_by")] + public string updateBy { get; set; } + + /// + /// 更新时间 + /// + [Column("update_time")] + public DateTime? updateTime { get; set; } + + /// + /// 绑定数量 + /// + [Column("bind_amount")] + public decimal? bindAmount { get; set; } + } +} + diff --git a/src/Khd.Core.Domain/Models/MesBaseUnitInfo.cs b/src/Khd.Core.Domain/Models/MesBaseUnitInfo.cs new file mode 100644 index 0000000..e2e0ab1 --- /dev/null +++ b/src/Khd.Core.Domain/Models/MesBaseUnitInfo.cs @@ -0,0 +1,87 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations.Schema; +using System.ComponentModel.DataAnnotations; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Khd.Core.Domain.Models +{ + [Table("mes_base_unit_info")] + public class MesBaseUnitInfo + { + /// + /// 主键标识 + /// + [Key] + [Column("unit_id")] + public long UnitId { get; set; } + + /// + /// 供应商编号;对应FNumber + /// + [Column("unit_code")] + public string UnitCode { get; set; } + + /// + /// 供应商名称;对应FName + /// + [Column("unit_name")] + public string UnitName { get; set; } + + /// + /// erp的主键;对应FUnitId + /// + [Column("erp_id")] + public long? ErpId { get; set; } + + /// + /// 单位状态:1-启用;0-停用 + /// + [Column("unit_status")] + public string UnitStatus { get; set; } = "1"; + + /// + /// 备注 + /// + [Column("remark")] + public string Remark { get; set; } + + /// + /// 创建人 + /// + [Column("create_by")] + public string CreateBy { get; set; } + + /// + /// 创建时间;对应FCreateDate + /// + [Column("create_time")] + public DateTime? CreateTime { get; set; } + + /// + /// 更新人 + /// + [Column("update_by")] + public string UpdateBy { get; set; } + + /// + /// 更新时间 + /// + [Column("update_time")] + public DateTime? UpdateTime { get; set; } + + /// + /// 审核日期;对应FAuditDate + /// + [Column("audit_date")] + public DateTime? AuditDate { get; set; } + + /// + /// erp最后更新时间;对应FModifyDate + /// + [Column("erp_modify_date")] + public DateTime? ErpModifyDate { get; set; } + } +} \ No newline at end of file diff --git a/src/Khd.Core.Domain/Models/MesProdPlan.cs b/src/Khd.Core.Domain/Models/MesProdPlan.cs new file mode 100644 index 0000000..6e69e27 --- /dev/null +++ b/src/Khd.Core.Domain/Models/MesProdPlan.cs @@ -0,0 +1,62 @@ + +//----------------------------------------------------------------------- +// +// * Copyright (C) 2021 KEHAIDASOFT All Rights Reserved +// * version : 4.0.30319.42000 +// * author : khd by t4-2 +// +//----------------------------------------------------------------------- + +using System; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; + +namespace Khd.Core.Domain.Models +{ + + [Table("mes_prod_plan")] + public class MesProdPlan + { + + [Key] + [Column("ID")] + public Guid ID { get; set; } + + /// + /// VIN_CODE + /// + [Column("VIN_CODE")] + public string VIN_CODE { get; set; } + + /// + /// 物料描述 + /// + [Column("MATERIAL_DESC")] + public string MATERIAL_DESC { get; set; } + + /// + /// 线别 + /// + [Column("LINE")] + public string LINE { get; set; } + + /// + /// 数量 + /// + [Column("ORDER_QTY")] + public string ORDER_QTY { get; set; } + + /// + /// 时间 + /// + [Column("CREATE_TIME")] + public string? CREATE_TIME { get; set; } + + /// + /// 处理标志 0 接收 1 已处理 + /// + [Column("FLAG")] + public string FLAG { get; set; } + } +} + diff --git a/src/Khd.Core.Domain/Models/MesProductPlanDetail.cs b/src/Khd.Core.Domain/Models/MesProductPlanDetail.cs new file mode 100644 index 0000000..42c37c2 --- /dev/null +++ b/src/Khd.Core.Domain/Models/MesProductPlanDetail.cs @@ -0,0 +1,136 @@ + +//----------------------------------------------------------------------- +// +// * Copyright (C) 2021 KEHAIDASOFT All Rights Reserved +// * version : 4.0.30319.42000 +// * author : khd by t4-2 +// +//----------------------------------------------------------------------- + +using System; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; + +namespace Khd.Core.Domain.Models +{ + [Table("mes_product_plan_detail")] + public class MesProductPlanDetail + { + [Key] + [Column("plan_detail_id")] + public long PlanDetailId { get; set; } + + /// + /// 明细编号 + /// + [Column("plan_detail_code")] + [Required] + [StringLength(64)] + public string PlanDetailCode { get; set; } + + /// + /// 生产计划ID + /// + [Column("plan_id")] + [Required] + public long PlanId { get; set; } + + /// + /// 计划编号, 关联mes_product_plan_info的plan_code + /// + [Column("plan_code")] + [Required] + [StringLength(64)] + public string PlanCode { get; set; } + + /// + /// 操作人员ID,关联sys_user的user_id + /// + [Column("user_id")] + public long? UserId { get; set; } + + /// + /// 操作人员名称,关联sys_user的user_name + /// + [Column("user_name")] + [StringLength(64)] + public string UserName { get; set; } + + /// + /// 开始时间 + /// + [Column("real_begin_time")] + public DateTime? RealBeginTime { get; set; } + + /// + /// 完成时间 + /// + [Column("real_end_time")] + public DateTime? RealEndTime { get; set; } + + /// + /// 文件ID,关联附件信息主键 + /// + [Column("attach_id")] + public int? AttachId { get; set; } + + /// + /// 明细状态:1-未开始;2-已开始;3-已完成;9-异常完成(校验物料信息不完整) + /// + [Column("plan_detail_status")] + [Required] + [StringLength(1)] + public string PlanDetailStatus { get; set; } = "1"; + + /// + /// 是否标识:1-是;0-否 + /// + [Column("is_flag")] + [Required] + [StringLength(1)] + public string IsFlag { get; set; } = "1"; + + /// + /// 备注 + /// + [Column("remark")] + [StringLength(500)] + public string Remark { get; set; } + + /// + /// 创建人 + /// + [Column("create_by")] + [StringLength(64)] + public string CreateBy { get; set; } + + /// + /// 创建时间 + /// + [Column("create_time")] + public DateTime? CreateTime { get; set; } + + /// + /// 更新人 + /// + [Column("update_by")] + [StringLength(64)] + public string UpdateBy { get; set; } + + /// + /// 更新时间 + /// + [Column("update_time")] + public DateTime? UpdateTime { get; set; } + + /// + /// 物料条码 + /// + [Column("material_barcode")] + [StringLength(64)] + public string MaterialBarcode { get; set; } + } + + +} + diff --git a/src/Khd.Core.Domain/Models/MesSaleOrderRelate.cs b/src/Khd.Core.Domain/Models/MesSaleOrderRelate.cs new file mode 100644 index 0000000..729f4a6 --- /dev/null +++ b/src/Khd.Core.Domain/Models/MesSaleOrderRelate.cs @@ -0,0 +1,41 @@ + +//----------------------------------------------------------------------- +// +// * Copyright (C) 2021 KEHAIDASOFT All Rights Reserved +// * version : 4.0.30319.42000 +// * author : khd by t4-2 +// +//----------------------------------------------------------------------- + +using System; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; + +namespace Khd.Core.Domain.Models +{ + + [Table("mes_sale_order_relate")] + public class MesSaleOrderRelate + { + [Key] + [Column("sale_order_relate_id")] + public long SaleOrderRelateId { get; set; } + + [Column("sale_order_id")] + public long SaleOrderId { get; set; } + + [Column("relate_sale_order_id")] + public long RelateSaleOrderId { get; set; } + + [Column("purchase_order_id")] + public long PurchaseOrderId { get; set; } + + [Column("relate_sale_order_amout")] + public decimal RelateSaleOrderAmount { get; set; } + + [Column("material_id")] + public long MaterialId { get; set; } + + } +} + diff --git a/src/Khd.Core.Domain/Models/NewMaterial.cs b/src/Khd.Core.Domain/Models/NewMaterial.cs new file mode 100644 index 0000000..e246869 --- /dev/null +++ b/src/Khd.Core.Domain/Models/NewMaterial.cs @@ -0,0 +1,38 @@ + +//----------------------------------------------------------------------- +// +// * Copyright (C) 2021 KEHAIDASOFT All Rights Reserved +// * version : 4.0.30319.42000 +// * author : khd by t4-2 +// +//----------------------------------------------------------------------- + +using System; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; + +namespace Khd.Core.Domain.Models +{ + + [Table("new_material")] + public class NewMaterial + { + + [Key] + [Column("id")] + public Guid id { get; set; } + + [Column("barcode")] + public string barcode { get; set; } + + [Column("is_new")] + public int? isNew { get; set; } + + [Column("create_time")] + public DateTime? createTime { get; set; } + + [Column("site_node")] + public string siteNode { get; set; } + } +} + diff --git a/src/Khd.Core.Domain/Models/PlcPoint.cs b/src/Khd.Core.Domain/Models/PlcPoint.cs new file mode 100644 index 0000000..7b0eb74 --- /dev/null +++ b/src/Khd.Core.Domain/Models/PlcPoint.cs @@ -0,0 +1,29 @@ +using System.ComponentModel.DataAnnotations.Schema; + +namespace Khd.Core.Domain.Models +{ + [Table("wcs_Plc_Point")] + public class PlcPoint + { + [Column("id")] + public int Id { get; set; } + + [Column("plcpoint_no")] + public string PlcPoint_No { get; set; } + + [Column("plcpoint_name")] + public string PlcPoint_Name { get; set; } + + [Column("plcpoint_address")] + public string PlcPoint_Address { get; set; } + + [Column("equipment_no")] + public string Equipment_No { get; set; } + + [Column("floor_no")] + public int Floor_No { get; set; } + + [Column("plc_code")] + public int Plc_Code { get; set; } + } +} diff --git a/src/Khd.Core.Domain/Models/WcsCmd.cs b/src/Khd.Core.Domain/Models/WcsCmd.cs new file mode 100644 index 0000000..4593ade --- /dev/null +++ b/src/Khd.Core.Domain/Models/WcsCmd.cs @@ -0,0 +1,157 @@ + +//----------------------------------------------------------------------- +// +// * Copyright (C) 2021 KEHAIDASOFT All Rights Reserved +// * version : 4.0.30319.42000 +// * author : khd by t4-2 +// +//----------------------------------------------------------------------- + +using System; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; + +namespace Khd.Core.Domain.Models +{ + + [Table("wcs_cmd")] + public class WcsCmd + { + /// + /// 任务代码 + /// + [Column("task_code")] + public string taskCode { get; set; } + + [Key] + [Column("objid")] + public long objid { get; set; } + + /// + /// 任务id + /// + [Column("task_id")] + public long? taskId { get; set; } + + /// + /// 设备编号 + /// + [Column("equipment_no")] + public string equipmentNo { get; set; } + + /// + /// 容器号 + /// + [Column("container_no")] + public string containerNo { get; set; } + + /// + /// 指令类型,字典表 + /// + [Column("cmd_type")] + public int? cmdType { get; set; } + + /// + /// 数量 + /// + [Column("qty")] + public int? qty { get; set; } + + /// + /// 流水号 + /// + [Column("serial_no")] + public long? serialNo { get; set; } + + /// + /// 当前点编号 + /// + [Column("curr_point_no")] + public string currPointNo { get; set; } + + /// + /// 当前点id + /// + [Column("curr_point_id")] + public long? currPointId { get; set; } + + /// + /// 下一点编号 + /// + [Column("next_point_no")] + public string nextPointNo { get; set; } + + /// + /// 下一点id + /// + [Column("next_point_id")] + public long? nextPointId { get; set; } + + /// + /// 指令状态,字典表 + /// + [Column("cmd_status")] + public int? cmdStatus { get; set; } + + /// + /// 是否可用 0:不可用 1:可用 + /// + [Column("use_flag")] + public int? useFlag { get; set; } + + /// + /// 创建者 + /// + [Column("create_by")] + public string createBy { get; set; } + + /// + /// 创建时间 + /// + [Column("create_time")] + public DateTime? createTime { get; set; } + + /// + /// 更新者 + /// + [Column("update_by")] + public string updateBy { get; set; } + + /// + /// 更新时间 + /// + [Column("update_time")] + public DateTime? updateTime { get; set; } + + /// + /// 备用字段1 + /// + [Column("ud1")] + public string ud1 { get; set; } + + /// + /// 备用字段2 + /// + [Column("ud2")] + public string ud2 { get; set; } + + /// + /// 备用字段3 + /// + [Column("ud3")] + public string ud3 { get; set; } + + /// + /// 备注 + /// + [Column("remark")] + public string remark { get; set; } + /// + /// 下发标志 + /// + [Column("send_flag")] + public int? sendFlag { get; set; } + + } +} + diff --git a/src/Khd.Core.Domain/Models/WcsCmdLog.cs b/src/Khd.Core.Domain/Models/WcsCmdLog.cs new file mode 100644 index 0000000..a27e5d6 --- /dev/null +++ b/src/Khd.Core.Domain/Models/WcsCmdLog.cs @@ -0,0 +1,159 @@ + +//----------------------------------------------------------------------- +// +// * Copyright (C) 2021 KEHAIDASOFT All Rights Reserved +// * version : 4.0.30319.42000 +// * author : khd by t4-2 +// +//----------------------------------------------------------------------- + +using System; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; + +namespace Khd.Core.Domain.Models +{ + + [Table("wcs_cmd_log")] + public class WcsCmdLog + { + /// + /// 任务代码 + /// + [Column("task_code")] + public string taskCode { get; set; } + /// + /// 主键 + /// + [Column("objid")] + [Key] + public long objid { get; set; } + + /// + /// 任务id + /// + [Column("task_id")] + public long? taskId { get; set; } + + /// + /// 设备id + /// + [Column("equip_id")] + public long? equipId { get; set; } + + /// + /// 容器号 + /// + [Column("container_no")] + public string containerNo { get; set; } + + /// + /// 指令类型,字典表 + /// + [Column("cmd_type")] + public int? cmdType { get; set; } + + /// + /// 数量 + /// + [Column("qty")] + public int? qty { get; set; } + + /// + /// 流水号 + /// + [Column("serial_no")] + public long? serialNo { get; set; } + + /// + /// 当前点编号 + /// + [Column("curr_point_no")] + public string currPointNo { get; set; } + + /// + /// 当前点id + /// + [Column("curr_point_id")] + public long? currPointId { get; set; } + + /// + /// 下一点编号 + /// + [Column("next_point_no")] + public string nextPointNo { get; set; } + + /// + /// 下一点id + /// + [Column("next_point_id")] + public long? nextPointId { get; set; } + + /// + /// 指令状态,字典表 + /// + [Column("cmd_status")] + public int? cmdStatus { get; set; } + + /// + /// 是否可用 0:不可用 1:可用 + /// + [Column("use_flag")] + public int? useFlag { get; set; } + + /// + /// 创建者 + /// + [Column("create_by")] + public string createBy { get; set; } + + /// + /// 创建时间 + /// + [Column("create_time")] + public DateTime? createTime { get; set; } + + /// + /// 更新者 + /// + [Column("update_by")] + public string updateBy { get; set; } + + /// + /// 更新时间 + /// + [Column("update_time")] + public DateTime? updateTime { get; set; } + + /// + /// 备用字段1 + /// + [Column("ud1")] + public string ud1 { get; set; } + + /// + /// 备用字段2 + /// + [Column("ud2")] + public string ud2 { get; set; } + + /// + /// 备用字段3 + /// + [Column("ud3")] + public string ud3 { get; set; } + + /// + /// 备注 + /// + [Column("remark")] + public string remark { get; set; } + + /// + /// 下发标志 0未下发 1 已下发 + /// + [Column("send_flag")] + public int? sendFlag { get; set; } + } +} + diff --git a/src/Khd.Core.Domain/Models/WcsInWareOrder.cs b/src/Khd.Core.Domain/Models/WcsInWareOrder.cs new file mode 100644 index 0000000..2b1e6f4 --- /dev/null +++ b/src/Khd.Core.Domain/Models/WcsInWareOrder.cs @@ -0,0 +1,122 @@ + +//----------------------------------------------------------------------- +// +// * Copyright (C) 2021 KEHAIDASOFT All Rights Reserved +// * version : 4.0.30319.42000 +// * author : khd by t4-2 +// +//----------------------------------------------------------------------- + +using System; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; + +namespace Khd.Core.Domain.Models +{ + + [Table("wcs_in_ware_order")] + public class WcsInWareOrder + { + + [Key] + [Column("objid")] + public long objid { get; set; } + + /// + /// 任务id + /// + [Column("taskid")] + public long? taskid { get; set; } + + /// + /// 物料id + /// + [Column("material_id")] + public long? materialId { get; set; } + + /// + /// 物料编码 + /// + [Column("material_code")] + public string materialCode { get; set; } + + /// + /// 物料类型 + /// + [Column("material_type")] + public string materialType { get; set; } + + /// + /// 所属楼层 + /// + [Column("floor_no")] + public int? floorNo { get; set; } + + /// + /// 数量 + /// + [Column("qty")] + public int? qty { get; set; } + + /// + /// 库位编码 + /// + [Column("location_code")] + public string locationCode { get; set; } + + /// + /// 是否可用 0:不可用 1:可用 + /// + [Column("use_flag")] + public int? useFlag { get; set; } + + /// + /// 创建者 + /// + [Column("create_by")] + public string createBy { get; set; } + + /// + /// 创建时间 + /// + [Column("create_time")] + public DateTime? createTime { get; set; } + + /// + /// 更新者 + /// + [Column("update_by")] + public string updateBy { get; set; } + + /// + /// 更新时间 + /// + [Column("update_time")] + public DateTime? updateTime { get; set; } + + /// + /// 备用字段1 + /// + [Column("ud1")] + public string ud1 { get; set; } + + /// + /// 备用字段2 + /// + [Column("ud2")] + public string ud2 { get; set; } + + /// + /// 备用字段3 + /// + [Column("ud3")] + public string ud3 { get; set; } + + /// + /// 备注 + /// + [Column("remark")] + public string remark { get; set; } + } +} + diff --git a/src/Khd.Core.Domain/Models/WcsOutWareOrder.cs b/src/Khd.Core.Domain/Models/WcsOutWareOrder.cs new file mode 100644 index 0000000..e839233 --- /dev/null +++ b/src/Khd.Core.Domain/Models/WcsOutWareOrder.cs @@ -0,0 +1,122 @@ + +//----------------------------------------------------------------------- +// +// * Copyright (C) 2021 KEHAIDASOFT All Rights Reserved +// * version : 4.0.30319.42000 +// * author : khd by t4-2 +// +//----------------------------------------------------------------------- + +using System; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; + +namespace Khd.Core.Domain.Models +{ + + [Table("wcs_out_ware_order")] + public class WcsOutWareOrder + { + + [Key] + [Column("objid")] + public long objid { get; set; } + + /// + /// 任务id + /// + [Column("taskid")] + public long? taskid { get; set; } + + /// + /// 物料id + /// + [Column("material_id")] + public long? materialId { get; set; } + + /// + /// 物料编码 + /// + [Column("material_code")] + public string materialCode { get; set; } + + /// + /// 物料类型 + /// + [Column("material_type")] + public string materialType { get; set; } + + /// + /// 所属楼层 + /// + [Column("floor_no")] + public int? floorNo { get; set; } + + /// + /// 数量 + /// + [Column("qty")] + public int? qty { get; set; } + + /// + /// 库位编码 + /// + [Column("location_code")] + public string locationCode { get; set; } + + /// + /// 是否可用 0:不可用 1:可用 + /// + [Column("use_flag")] + public int? useFlag { get; set; } + + /// + /// 创建者 + /// + [Column("create_by")] + public string createBy { get; set; } + + /// + /// 创建时间 + /// + [Column("create_time")] + public DateTime? createTime { get; set; } + + /// + /// 更新者 + /// + [Column("update_by")] + public string updateBy { get; set; } + + /// + /// 更新时间 + /// + [Column("update_time")] + public DateTime? updateTime { get; set; } + + /// + /// 备用字段1 + /// + [Column("ud1")] + public string ud1 { get; set; } + + /// + /// 备用字段2 + /// + [Column("ud2")] + public string ud2 { get; set; } + + /// + /// 备用字段3 + /// + [Column("ud3")] + public string ud3 { get; set; } + + /// + /// 备注 + /// + [Column("remark")] + public string remark { get; set; } + } +} + diff --git a/src/Khd.Core.Domain/Models/WcsOutstockLock.cs b/src/Khd.Core.Domain/Models/WcsOutstockLock.cs new file mode 100644 index 0000000..c4a60f1 --- /dev/null +++ b/src/Khd.Core.Domain/Models/WcsOutstockLock.cs @@ -0,0 +1,140 @@ + +//----------------------------------------------------------------------- +// +// * Copyright (C) 2021 KEHAIDASOFT All Rights Reserved +// * version : 4.0.30319.42000 +// * author : khd by t4-2 +// +//----------------------------------------------------------------------- + +using System; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; + +namespace Khd.Core.Domain.Models +{ + + [Table("wcs_outstock_lock")] + public class WcsOutstockLock + { + + [Key] + [Column("objid")] + public long objid { get; set; } + + /// + /// wms申请单id + /// + [Column("wms_order_id")] + public long? wmsOrderId { get; set; } + + /// + /// wms申请单子表id + /// + [Column("wms_order_detail_id")] + public long? wmsOrderDetailId { get; set; } + + /// + /// 任务id + /// + [Column("task_id")] + public long? taskId { get; set; } + + /// + /// 单据类型(1 入库 2 出库 3 移库) + /// + [Column("order_type")] + public int? orderType { get; set; } + + /// + /// 物料id + /// + [Column("material_id")] + public long? materialId { get; set; } + + /// + /// 仓库id + /// + [Column("warehouse_id")] + public long? warehouseId { get; set; } + + /// + /// 料箱编号 + /// + [Column("box_no")] + public string boxNo { get; set; } + + /// + /// 料箱状态 + /// + [Column("box_status")] + public int? boxStatus { get; set; } + + /// + /// 所属楼层 + /// + [Column("floor_num")] + public int? floorNum { get; set; } + + /// + /// 数量 + /// + [Column("qty")] + public decimal? qty { get; set; } + + /// + /// 是否可用 0:不可用 1:可用 + /// + [Column("use_flag")] + public int? useFlag { get; set; } + + /// + /// 创建者 + /// + [Column("create_by")] + public string createBy { get; set; } + + /// + /// 创建时间 + /// + [Column("create_time")] + public DateTime? createTime { get; set; } + + /// + /// 更新者 + /// + [Column("update_by")] + public string updateBy { get; set; } + + /// + /// 更新时间 + /// + [Column("update_time")] + public DateTime? updateTime { get; set; } + + /// + /// 备用字段1 + /// + [Column("ud1")] + public string ud1 { get; set; } + + /// + /// 备用字段2 + /// + [Column("ud2")] + public string ud2 { get; set; } + + /// + /// 备用字段3 + /// + [Column("ud3")] + public string ud3 { get; set; } + + /// + /// 备注 + /// + [Column("REMARK")] + public string remark { get; set; } + } +} + diff --git a/src/Khd.Core.Domain/Models/WcsStock.cs b/src/Khd.Core.Domain/Models/WcsStock.cs new file mode 100644 index 0000000..0a6edd1 --- /dev/null +++ b/src/Khd.Core.Domain/Models/WcsStock.cs @@ -0,0 +1,134 @@ + +//----------------------------------------------------------------------- +// +// * Copyright (C) 2021 KEHAIDASOFT All Rights Reserved +// * version : 4.0.30319.42000 +// * author : khd by t4-2 +// +//----------------------------------------------------------------------- + +using System; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; + +namespace Khd.Core.Domain.Models +{ + + [Table("wcs_stock")] + public class WcsStock + { + + [Key] + [Column("objid")] + public long objid { get; set; } + + /// + /// 物料主键 + /// + [Column("material_id")] + public long? materialId { get; set; } + + /// + /// 物料编码 + /// + [Column("material_code")] + public string materialCode { get; set; } + + /// + /// 物料名称 + /// + [Column("material_name")] + public string materialName { get; set; } + + /// + /// 物料类型 + /// + [Column("material_type")] + public string materialType { get; set; } + + /// + /// 仓库主键 + /// + [Column("warehouse_id")] + public long? warehouseId { get; set; } + + /// + /// 库位编码 + /// + [Column("location_code")] + public string locationCode { get; set; } + + /// + /// 库位名称 + /// + [Column("location_name")] + public string locationName { get; set; } + + /// + /// 层 + /// + [Column("layer_no")] + public int? layerNo { get; set; } + + /// + /// 列 + /// + [Column("col_no")] + public int? colNo { get; set; } + + /// + /// 排 + /// + [Column("row_no")] + public int? rowNo { get; set; } + + /// + /// 深位 + /// + [Column("deep_no")] + public int? deepNo { get; set; } + + /// + /// 楼层编号 + /// + [Column("floor_no")] + public int? floorNo { get; set; } + + /// + /// 是否可用 0:不可用 1:可用 + /// + [Column("use_flag")] + public int? useFlag { get; set; } + + /// + /// 创建者 + /// + [Column("create_by")] + public string createBy { get; set; } + + /// + /// 创建时间 + /// + [Column("create_time")] + public DateTime? createTime { get; set; } + + /// + /// 更新者 + /// + [Column("update_by")] + public string updateBy { get; set; } + + /// + /// 更新时间 + /// + [Column("update_time")] + public DateTime? updateTime { get; set; } + + /// + /// 备注 + /// + [Column("remark")] + public string remark { get; set; } + } +} + diff --git a/src/Khd.Core.Domain/Models/WcsTask.cs b/src/Khd.Core.Domain/Models/WcsTask.cs new file mode 100644 index 0000000..b97026d --- /dev/null +++ b/src/Khd.Core.Domain/Models/WcsTask.cs @@ -0,0 +1,223 @@ + +//----------------------------------------------------------------------- +// +// * Copyright (C) 2021 KEHAIDASOFT All Rights Reserved +// * version : 4.0.30319.42000 +// * author : khd by t4-2 +// +//----------------------------------------------------------------------- + +using System; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; + +namespace Khd.Core.Domain.Models +{ + + [Table("wcs_task")] + public class WcsTask + { + [Column("taskCode")] + public string taskCode { get; set; } + [Column("from_floor_no")] + public int? fromFloorNo { get; set; } + + [Key] + [Column("objid")] + public long objid { get; set; } + + /// + /// wcs_warehouse_order 主键id + /// + [Column("master_id")] + public long? masterId { get; set; }//暂时不用 + + /// + /// wms出入库记录表id + /// + [Column("order_id")] + public long? orderId { get; set; }//申请单的主键id + + /// + /// 流水号 + /// + [Column("serial_no")] + public long? serialNo { get; set; }//提升机专用流水号 + + /// + /// 设备编号 + /// + [Column("equipment_no")] + public string equipmentNo { get; set; }//设备编号 + + /// + /// 容器号(托盘或者箱号) + /// + [Column("container_no")] + public string containerNo { get; set; }//RFID,料箱号 + + /// + /// 任务类型,字典表 + /// 27提升机输送线对接位-验收拆分区 + /// 28验收拆分区-原材料周转区 + /// 29回转输送线回库口-辅料库货架 + /// 30辅料库货架-回转输送线出库口 + /// 31回转输送线回库口-辅料库货架 + /// 32物料分拣位-装配区领料工位 + /// 33原材料周转区-背板安装区 + /// 34背板安装区-半成品周转区 + /// 35半成品周转区-检测台 + /// 37检验台-成品区 + /// 38成品区-提升机输送线对接点 + /// 46原材料-柜体拆分区 + /// 47接驳位-原材料周转区 + /// + [Column("task_type")] + public int? taskType { get; set; }//对照数据库wcs_base_dictionary表的主键27开始 + + /// + /// 任务状态,字典表 + /// + [Column("task_status")] + public int? taskStatus { get; set; } + + /// + /// 物料ID + /// + [Column("material_id")] + public long? materialId { get; set; } + + /// + /// 物料号 + /// + [Column("material_no")] + public string? materialBarcode { get; set; } + + /// + /// 数量 + /// + [Column("qty")] + public int? qty { get; set; } + + ///// + ///// 起始点编号 + ///// + //[Column("start_point_no")] + //public string startPointNo { get; set; } + + ///// + ///// 起始点id + ///// + //[Column("start_point_id")] + //public long? startPointId { get; set; } + + /// + /// 当前点编号 + /// + [Column("curr_point_no")] + public string currPointNo { get; set; } + + /// + /// 当前点id + /// + [Column("curr_point_id")] + public long? currPointId { get; set; } + + /// + /// 下一点位id + /// + [Column("next_point_id")] + public long? nextPointId { get; set; } + + /// + /// 下一点位编号 + /// + [Column("next_point_no")] + public string nextPointNo { get; set; } + + /// + /// 结束点编号 + /// + [Column("end_point_no")] + public string endPointNo { get; set; } + + /// + /// 结束点id + /// + [Column("end_point_id")] + public long? endPointId { get; set; } + + /// + /// 所属楼层 + /// + [Column("floor_no")] + public int? floorNo { get; set; } + + /// + /// 是否可用 0:不可用 1:可用 + /// + [Column("use_flag")] + public int? useFlag { get; set; } + + /// + /// 创建者 + /// + [Column("create_by")] + public string createBy { get; set; } + + /// + /// 创建时间 + /// + [Column("create_time")] + public DateTime? createTime { get; set; } + + /// + /// 更新者 + /// + [Column("update_by")] + public string updateBy { get; set; } + + /// + /// 更新时间 + /// + [Column("update_time")] + public DateTime? updateTime { get; set; } + + /// + /// 备用字段1 + /// + [Column("ctu_execute")] + public string CTUExecute { get; set; } + + /// + /// 备用字段2 + /// + [Column("is_empty")] + public string isEmpty { get; set; } + + /// + /// 备用字段3 + /// + [Column("ud3")] + public string ud3 { get; set; } + /// + /// 备用字段3 + /// + [Column("ud1")] + public int? ud1 { get; set; } + /// + /// 备用字段3 + /// + [Column("ud2")] + public string ud2 { get; set; } + /// + /// 备注 + /// + [Column("remark")] + public string remark { get; set; } + + [Column("is_delete")] + public int? IsDelete { get; set; } + } +} + diff --git a/src/Khd.Core.Domain/Models/WcsTaskLog.cs b/src/Khd.Core.Domain/Models/WcsTaskLog.cs new file mode 100644 index 0000000..74658c9 --- /dev/null +++ b/src/Khd.Core.Domain/Models/WcsTaskLog.cs @@ -0,0 +1,225 @@ + +//----------------------------------------------------------------------- +// +// * Copyright (C) 2021 KEHAIDASOFT All Rights Reserved +// * version : 4.0.30319.42000 +// * author : khd by t4-2 +// +//----------------------------------------------------------------------- + +using System; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; + +namespace Khd.Core.Domain.Models +{ + + [Table("wcs_task_log")] + public class WcsTaskLog + { + [Column("taskCode")] + public string taskCode { get; set; } + [Column("from_floor_no")] + public int? fromFloorNo { get; set; } + + [Key] + [Column("objid")] + public long objid { get; set; } + + /// + /// wcs_warehouse_order 主键id + /// + [Column("master_id")] + public long? masterId { get; set; } + + /// + /// wms出入库记录表id + /// + [Column("order_id")] + public long? orderId { get; set; } + + /// + /// 流水号 + /// + [Column("serial_no")] + public long? serialNo { get; set; } + + /// + /// 设备编号 + /// + [Column("equipment_no")] + public string equipmentNo { get; set; } + + /// + /// 容器号(托盘或者箱号) + /// + [Column("container_no")] + public string containerNo { get; set; } + + /// + /// 任务类型,字典表 + /// 27提升机输送线对接位-验收拆分区 + /// 28验收拆分区-原材料周转区 + /// 29回转输送线回库口-辅料库货架 + /// 30辅料库货架-回转输送线出库口 + /// 31回转输送线回库口-辅料库货架 + /// 32物料分拣位-装配区领料工位 + /// 33原材料周转区-背板安装区 + /// 34背板安装区-半成品周转区 + /// 35半成品周转区-检测台 + /// 37检验台-成品区 + /// 38成品区-提升机输送线对接点 + /// 46原材料-柜体拆分区 + /// 47接驳位-原材料周转区 + /// + /// + /// + [Column("task_type")] + public int? taskType { get; set; } + + /// + /// 任务状态,字典表 + /// + [Column("task_status")] + public int? taskStatus { get; set; } + + /// + /// 物料ID + /// + [Column("material_id")] + public long? materialId { get; set; } + + /// + /// 物料号 + /// + [Column("material_no")] + public string? materialBarcode { get; set; } + + /// + /// 数量 + /// + [Column("qty")] + public int? qty { get; set; } + + /// + /// 起始点编号 + /// + [Column("start_point_no")] + public string startPointNo { get; set; } + + /// + /// 起始点id + /// + [Column("start_point_id")] + public long? startPointId { get; set; } + + /// + /// 当前点编号 + /// + [Column("curr_point_no")] + public string currPointNo { get; set; } + + /// + /// 当前点id + /// + [Column("curr_point_id")] + public long? currPointId { get; set; } + + /// + /// 下一点位id + /// + [Column("next_point_id")] + public long? nextPointId { get; set; } + + /// + /// 下一点位编号 + /// + [Column("next_point_no")] + public string nextPointNo { get; set; } + + /// + /// 结束点编号 + /// + [Column("end_point_no")] + public string endPointNo { get; set; } + + /// + /// 结束点id + /// + [Column("end_point_id")] + public long? endPointId { get; set; } + + /// + /// 所属楼层 + /// + [Column("floor_no")] + public int? floorNo { get; set; } + + /// + /// 是否可用 0:不可用 1:可用 + /// + [Column("use_flag")] + public int? useFlag { get; set; } + + /// + /// 创建者 + /// + [Column("create_by")] + public string createBy { get; set; } + + /// + /// 创建时间 + /// + [Column("create_time")] + public DateTime? createTime { get; set; } + + /// + /// 更新者 + /// + [Column("update_by")] + public string updateBy { get; set; } + + /// + /// 更新时间 + /// + [Column("update_time")] + public DateTime? updateTime { get; set; } + + /// + /// 备用字段1 + /// + [Column("ctu_execute")] + public string CTUExecute { get; set; } + + /// + /// 备用字段2 + /// + [Column("is_empty")] + public string isEmpty { get; set; } + + /// + /// 备用字段3 + /// + [Column("ud3")] + public string ud3 { get; set; } + /// + /// 备用字段3 + /// + [Column("ud1")] + public int? ud1 { get; set; } + /// + /// 备用字段3 + /// + [Column("ud2")] + public string ud2 { get; set; } + /// + /// 备注 + /// + [Column("remark")] + public string remark { get; set; } + + [Column("is_delete")] + public int? IsDelete { get; set; } + } +} + diff --git a/src/Khd.Core.Domain/Models/WcsTaskManual.cs b/src/Khd.Core.Domain/Models/WcsTaskManual.cs new file mode 100644 index 0000000..5d67039 --- /dev/null +++ b/src/Khd.Core.Domain/Models/WcsTaskManual.cs @@ -0,0 +1,211 @@ +using System; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; + +namespace Khd.Core.Domain.Models +{ + [Table("wcs_task_manual")] + public class WcsTaskManual + { + [Column("from_floor_no")] + public int? fromFloorNo { get; set; } + + [Key] + [Column("objid")] + public long objid { get; set; } + + /// + /// wcs_warehouse_order 主键id + /// + [Column("master_id")] + public long? masterId { get; set; } + + /// + /// wms出入库记录表id + /// + [Column("order_id")] + public long? orderId { get; set; } + + /// + /// 流水号 + /// + [Column("serial_no")] + public long? serialNo { get; set; } + + /// + /// 设备编号 + /// + [Column("equipment_no")] + public string equipmentNo { get; set; } + + /// + /// 容器号(托盘或者箱号) + /// + [Column("container_no")] + public string containerNo { get; set; } + + /// + /// 任务类型,字典表 + /// 27提升机输送线对接位-验收拆分区 + /// 28验收拆分区-原材料周转区 + /// 29回转输送线回库口-辅料库货架 + /// 30辅料库货架-回转输送线出库口 + /// 31回转输送线回库口-辅料库货架 + /// 32物料分拣位-装配区领料工位 + /// 33原材料周转区-背板安装区 + /// 34背板安装区-半成品周转区 + /// 35半成品周转区-检测台 + /// 37检验台-成品区 + /// 38成品区-提升机输送线对接点 + /// 46原材料-柜体拆分区 + /// 47接驳位-原材料周转区 + /// + /// + /// + [Column("task_type")] + public int? taskType { get; set; } + + /// + /// 任务状态,字典表 + /// + [Column("task_status")] + public int? taskStatus { get; set; } + + /// + /// 物料ID + /// + [Column("material_id")] + public long? materialId { get; set; } + + /// + /// 物料号 + /// + [Column("material_no")] + public string? materialBarcode { get; set; } + + /// + /// 数量 + /// + [Column("qty")] + public int? qty { get; set; } + + /// + /// 起始点编号 + /// + [Column("start_point_no")] + public string startPointNo { get; set; } + + /// + /// 起始点id + /// + [Column("start_point_id")] + public long? startPointId { get; set; } + + /// + /// 当前点编号 + /// + [Column("curr_point_no")] + public string currPointNo { get; set; } + + /// + /// 当前点id + /// + [Column("curr_point_id")] + public long? currPointId { get; set; } + + /// + /// 下一点位id + /// + [Column("next_point_id")] + public long? nextPointId { get; set; } + + /// + /// 下一点位编号 + /// + [Column("next_point_no")] + public string nextPointNo { get; set; } + + /// + /// 结束点编号 + /// + [Column("end_point_no")] + public string endPointNo { get; set; } + + /// + /// 结束点id + /// + [Column("end_point_id")] + public long? endPointId { get; set; } + + /// + /// 所属楼层 + /// + [Column("floor_no")] + public int? floorNo { get; set; } + + /// + /// 是否可用 0:不可用 1:可用 + /// + [Column("use_flag")] + public int? useFlag { get; set; } + + /// + /// 创建者 + /// + [Column("create_by")] + public string createBy { get; set; } + + /// + /// 创建时间 + /// + [Column("create_time")] + public DateTime? createTime { get; set; } + + /// + /// 更新者 + /// + [Column("update_by")] + public string updateBy { get; set; } + + /// + /// 更新时间 + /// + [Column("update_time")] + public DateTime? updateTime { get; set; } + + /// + /// 备用字段1 + /// + [Column("ctu_execute")] + public string CTUExecute { get; set; } + + /// + /// 备用字段2 + /// + [Column("is_empty")] + public string isEmpty { get; set; } + + /// + /// 备用字段3 + /// + [Column("ud3")] + public string ud3 { get; set; } + /// + /// 备用字段3 + /// + [Column("ud1")] + public int? ud1 { get; set; } + /// + /// 备用字段3 + /// + [Column("ud2")] + public string ud2 { get; set; } + /// + /// 备注 + /// + [Column("remark")] + public string remark { get; set; } + + + } +} diff --git a/src/Khd.Core.Domain/Models/WcsWarehouseOrder.cs b/src/Khd.Core.Domain/Models/WcsWarehouseOrder.cs new file mode 100644 index 0000000..6f8425d --- /dev/null +++ b/src/Khd.Core.Domain/Models/WcsWarehouseOrder.cs @@ -0,0 +1,116 @@ + +//----------------------------------------------------------------------- +// +// * Copyright (C) 2021 KEHAIDASOFT All Rights Reserved +// * version : 4.0.30319.42000 +// * author : khd by t4-2 +// +//----------------------------------------------------------------------- + +using System; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; + +namespace Khd.Core.Domain.Models +{ + + [Table("wcs_warehouse_order")] + public class WcsWarehouseOrder + { + + [Key] + [Column("objid")] + public long objid { get; set; } + + /// + /// wms申请单id + /// + [Column("wms_order_id")] + public long? wmsOrderId { get; set; } + + /// + /// 单据类型(1 入库 2 出库 3 移库) + /// + [Column("order_type")] + public int? orderType { get; set; } + + /// + /// 所属楼层 + /// + [Column("floor_num")] + public int? floorNum { get; set; } + + /// + /// 数量 + /// + [Column("qty")] + public int? qty { get; set; } + + /// + /// 单据状态(0 创建订单 1 订单执行中 2 订单完成) + /// + [Column("order_status")] + public int? orderStatus { get; set; } + + /// + /// 起始点编号 + /// + [Column("order_time")] + public string orderTime { get; set; } + + /// + /// 是否可用 0:不可用 1:可用 + /// + [Column("use_flag")] + public int? useFlag { get; set; } + + /// + /// 创建者 + /// + [Column("create_by")] + public string createBy { get; set; } + + /// + /// 创建时间 + /// + [Column("create_time")] + public DateTime? createTime { get; set; } + + /// + /// 更新者 + /// + [Column("update_by")] + public string updateBy { get; set; } + + /// + /// 更新时间 + /// + [Column("update_time")] + public DateTime? updateTime { get; set; } + + /// + /// 备用字段1 + /// + [Column("ud1")] + public string ud1 { get; set; } + + /// + /// 备用字段2 + /// + [Column("ud2")] + public string ud2 { get; set; } + + /// + /// 备用字段3 + /// + [Column("ud3")] + public string ud3 { get; set; } + + /// + /// 备注 + /// + [Column("REMARK")] + public string remark { get; set; } + } +} + diff --git a/src/Khd.Core.Domain/Models/WcsWarehouseOrderDetaile.cs b/src/Khd.Core.Domain/Models/WcsWarehouseOrderDetaile.cs new file mode 100644 index 0000000..d3fd226 --- /dev/null +++ b/src/Khd.Core.Domain/Models/WcsWarehouseOrderDetaile.cs @@ -0,0 +1,116 @@ + +//----------------------------------------------------------------------- +// +// * Copyright (C) 2021 KEHAIDASOFT All Rights Reserved +// * version : 4.0.30319.42000 +// * author : khd by t4-2 +// +//----------------------------------------------------------------------- + +using System; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; + +namespace Khd.Core.Domain.Models +{ + + [Table("wcs_warehouse_order_detaile")] + public class WcsWarehouseOrderDetaile + { + + [Key] + [Column("OBJID")] + public Guid objid { get; set; } + + /// + /// wms申请单id + /// + [Column("WMS_ORDER_ID")] + public string wmsOrderId { get; set; } + + /// + /// 单据类型 + /// + [Column("ORDER_TYPE")] + public int? orderType { get; set; } + + /// + /// 所属楼层 + /// + [Column("FLOOR_NUM")] + public int? floorNum { get; set; } + + /// + /// 数量 + /// + [Column("QTY")] + public int? qty { get; set; } + + /// + /// 单据状态 + /// + [Column("ORDER_STATUS")] + public int? orderStatus { get; set; } + + /// + /// 起始点编号 + /// + [Column("ORDER_TIME")] + public string orderTime { get; set; } + + /// + /// 是否可用 0:不可用 1:可用 + /// + [Column("USE_FLAG")] + public int? useFlag { get; set; } + + /// + /// 创建者 + /// + [Column("CREATE_BY")] + public string createBy { get; set; } + + /// + /// 创建时间 + /// + [Column("CREATE_TIME")] + public DateTime? createTime { get; set; } + + /// + /// 更新者 + /// + [Column("UPDATE_BY")] + public string updateBy { get; set; } + + /// + /// 更新时间 + /// + [Column("UPDATE_TIME")] + public DateTime? updateTime { get; set; } + + /// + /// 备用字段1 + /// + [Column("UD1")] + public string ud1 { get; set; } + + /// + /// 备用字段2 + /// + [Column("UD2")] + public string ud2 { get; set; } + + /// + /// 备用字段3 + /// + [Column("UD3")] + public string ud3 { get; set; } + + /// + /// 备注 + /// + [Column("REMARK")] + public string remark { get; set; } + } +} + diff --git a/src/Khd.Core.Domain/Models/WcsWarehouseOrderModel.cs b/src/Khd.Core.Domain/Models/WcsWarehouseOrderModel.cs new file mode 100644 index 0000000..0d02fab --- /dev/null +++ b/src/Khd.Core.Domain/Models/WcsWarehouseOrderModel.cs @@ -0,0 +1,113 @@ + +//----------------------------------------------------------------------- +// +// * Copyright (C) 2021 KEHAIDASOFT All Rights Reserved +// * version : 4.0.30319.42000 +// * author : khd by t4-2 +// +//----------------------------------------------------------------------- + +using System; +using System.ComponentModel.DataAnnotations.Schema; + +namespace Khd.Core.Domain.Models +{ + + [Table("wcs_warehouse_order")] + public class WcsWarehouseOrderModel + { + [Column("OBJID")] + public Guid objid { get; set; } + + /// + /// wms申请单id + /// + [Column("WMS_ORDER_ID")] + public string wmsOrderId { get; set; } + + /// + /// 单据类型(1 入库 2 出库 3 移库) + /// + [Column("ORDER_TYPE")] + public int? orderType { get; set; } + + /// + /// 所属楼层 + /// + [Column("FLOOR_NUM")] + public int? floorNum { get; set; } + + /// + /// 数量 + /// + [Column("QTY")] + public int? qty { get; set; } + + /// + /// 单据状态(0 创建订单 1 订单执行中 2 订单完成) + /// + [Column("ORDER_STATUS")] + public int? orderStatus { get; set; } + + /// + /// 起始点编号 + /// + [Column("ORDER_TIME")] + public string orderTime { get; set; } + + /// + /// 是否可用 0:不可用 1:可用 + /// + [Column("USE_FLAG")] + public int? useFlag { get; set; } + + /// + /// 创建者 + /// + [Column("CREATE_BY")] + public string createBy { get; set; } + + /// + /// 创建时间 + /// + [Column("CREATE_TIME")] + public DateTime? createTime { get; set; } + + /// + /// 更新者 + /// + [Column("UPDATE_BY")] + public string updateBy { get; set; } + + /// + /// 更新时间 + /// + [Column("UPDATE_TIME")] + public DateTime? updateTime { get; set; } + + /// + /// 备用字段1 + /// + [Column("UD1")] + public string ud1 { get; set; } + + /// + /// 备用字段2 + /// + [Column("UD2")] + public string ud2 { get; set; } + + /// + /// 备用字段3 + /// + [Column("UD3")] + public string ud3 { get; set; } + + /// + /// 备注 + /// + [Column("REMARK")] + public string remark { get; set; } + } +} + diff --git a/src/Khd.Core.Domain/Models/WmsBaseLocation.cs b/src/Khd.Core.Domain/Models/WmsBaseLocation.cs new file mode 100644 index 0000000..b4b0ce2 --- /dev/null +++ b/src/Khd.Core.Domain/Models/WmsBaseLocation.cs @@ -0,0 +1,235 @@ + +//----------------------------------------------------------------------- +// +// * Copyright (C) 2021 KEHAIDASOFT All Rights Reserved +// * version : 4.0.30319.42000 +// * author : khd by t4-2 +// +//----------------------------------------------------------------------- + +using System; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; + +namespace Khd.Core.Domain.Models +{ + + [Table("wms_base_location")] + public class WmsBaseLocation + { + + [Key] + [Column("location_id")] + public long locationId { get; set; } + + /// + /// 料箱号 + /// + [Column("container_code")] + public string containerCode { get; set; } + /// + /// 仓库ID,关联wms_base_warehouse的warehouse_id + /// + [Column("warehouse_id")] + public long warehouseId { get; set; } + + /// + /// agv的点位编码 + /// + [Column("agv_position_code")] + public string agvPositionCode { get; set; } + + [Column("warehouse_floor")] + public int? warehouseFloor { get; set; } + + /// + /// 库位编码 + /// + [Column("location_code")] + public string locationCode { get; set; } + + /// + /// 排 + /// + [Column("loc_row")] + public int? locRow { get; set; } + + /// + /// 层数 + /// + [Column("layer_num")] + public int? layerNum { get; set; } + + /// + /// 列 + /// + [Column("loc_column")] + public int? locColumn { get; set; } + + /// + /// 深位1 浅位2 + /// + [Column("loc_deep")] + public int? locDeep { get; set; } + + /// + /// 激活标记 1是 0否 + /// + [Column("active_flag")] + public string activeFlag { get; set; } + + /// + /// 人工处理标识(1是,0否),对于agv仓库可选择 + /// + [Column("manual_flag")] + public string manualFlag { get; set; } + + /// + /// 返库标识(1是0否);用来标识是否是拆分后返库的库位 + /// + [Column("return_flag")] + public string returnFlag { get; set; } + + /// + /// 数量限制 + /// + [Column("qty_limit")] + public decimal? qtyLimit { get; set; } + + ///// + ///// 入库过度库位标识(1:是,0:否) + ///// + //[Column("instock_flag")] + //public string instockFlag { get; set; } + + ///// + ///// 出库过度库位标识(1:是,0:否) + ///// + //[Column("outstock_flag")] + //public string outstockFlag { get; set; } + + /// + /// 库位状态(1:正常,2:自动锁定,3:人工锁定,4:移库锁定,5:合库锁定 6出库锁定);在正常时,库位可以使用,如果是自动锁定则需要自动解锁变成正常,如果是人工锁定需要人工解锁变成正常 + /// + [Column("location_status")] + public string locationStatus { get; set; } + + /// + /// 允许混放批次 1是 0否(预留,先不显示此字段);先按仓库的判断 + /// + [Column("batch_mix")] + public string batchMix { get; set; } + + /// + /// 创建者 + /// + [Column("create_by")] + public string createBy { get; set; } + + /// + /// 创建时间 + /// + [Column("create_time")] + public DateTime? createTime { get; set; } + + /// + /// 更新者 + /// + [Column("update_by")] + public string updateBy { get; set; } + + /// + /// 更新时间 + /// + [Column("update_time")] + public DateTime? updateTime { get; set; } + + /// + /// 备注 + /// + [Column("remark")] + public string remark { get; set; } + + /// + /// 删除标志 1删除 0显示 + /// + [Column("del_flag")] + public string delFlag { get; set; } + + /// + /// 上架顺序 + /// + [Column("shelf_order")] + public string shelfOrder { get; set; } + + /// + /// 盘点顺序 + /// + [Column("check_order")] + public string checkOrder { get; set; } + + /// + /// 拣货顺序 + /// + [Column("pick_order")] + public string pickOrder { get; set; } + + /// + /// 是否允许拣货 + /// + [Column("pick_flag")] + public string pickFlag { get; set; } + + /// + /// 是否开启库内交接 0:未开启 1:开启 + /// + [Column("is_open_kn_flag")] + public string isOpenKnFlag { get; set; } + + /// + /// 是否报废库位 1:正常 0:报废 + /// + [Column("location_scrap_type")] + public string locationScrapType { get; set; } + + /// + /// 体积限制 + /// + [Column("volume_limit")] + public decimal? volumeLimit { get; set; } + + /// + /// 重量限制 + /// + [Column("weight_limit")] + public decimal? weightLimit { get; set; } + + /// + /// 长度 + /// + [Column("length")] + public decimal? length { get; set; } + + /// + /// 宽度 + /// + [Column("width")] + public decimal? width { get; set; } + + /// + /// 高度 + /// + [Column("height")] + public decimal? height { get; set; } + + [Column("container_status")] + public string ContainerStatus { get; set; } + + /// + /// 异常描述 + /// + [Column("exception_desc")] + public string ExceptionDesc { get; set; } + } +} + diff --git a/src/Khd.Core.Domain/Models/WmsBaseWarehouse.cs b/src/Khd.Core.Domain/Models/WmsBaseWarehouse.cs new file mode 100644 index 0000000..cbab7bb --- /dev/null +++ b/src/Khd.Core.Domain/Models/WmsBaseWarehouse.cs @@ -0,0 +1,182 @@ + +//----------------------------------------------------------------------- +// +// * Copyright (C) 2021 KEHAIDASOFT All Rights Reserved +// * version : 4.0.30319.42000 +// * author : khd by t4-2 +// +//----------------------------------------------------------------------- + +using System; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; + +namespace Khd.Core.Domain.Models +{ + + [Table("wms_base_warehouse")] + public class WmsBaseWarehouse + { + + [Key] + [Column("warehouse_id")] + public long warehouseId { get; set; } + + /// + /// 存放类型(1原材料, 2半成品,3成品) + /// + [Column("warehouse_instock_type")] + public string warehouseInstockType { get; set; } + + /// + /// 仓库类型 1:普通仓库 2:背负agv仓库 3料箱agv仓库;背负agv仓库和料箱agv仓库审核标识为否 + /// + [Column("warehouse_type")] + public string warehouseType { get; set; } + + /// + /// 仓库编码 + /// + [Column("warehouse_code")] + public string warehouseCode { get; set; } + + /// + /// 仓库名称 + /// + [Column("warehouse_name")] + public string warehouseName { get; set; } + + /// + /// 仓库类别(关联wms_base_category的category_id) + /// + [Column("warehouse_category_id")] + public int? warehouseCategoryId { get; set; } + + /// + /// 楼层 + /// + [Column("warehouse_floor")] + public int warehouseFloor { get; set; } + + /// + /// 管辖部门(关联sys_dept的dept_id) + /// + [Column("dept_id")] + public long deptId { get; set; } + + /// + /// 多排库类型(1单排库,2双排库) + /// + [Column("multi_row_type")] + public string multiRowType { get; set; } + + /// + /// 多边库类型(1单面库,2双面库);料箱agv是两面的,叉车agv在两面库的中间进行输送,尽量一次让叉车输送同一面的额任务 + /// + [Column("multi_side_type")] + public string multiSideType { get; set; } + + /// + /// 允许混放批次(1是,0否) + /// + [Column("batch_mix")] + public string batchMix { get; set; } + + /// + /// 允许混放产品 1是 0否;预留,允许混放不同的产品 + /// + [Column("product_mix")] + public string productMix { get; set; } + + /// + /// 料箱标识(0否,1是) + /// + [Column("workbin_flag")] + public string workbinFlag { get; set; } + + /// + /// 位置 + /// + [Column("warehouse_location")] + public string warehouseLocation { get; set; } + + /// + /// 激活标记 1是 0否 + /// + [Column("active_flag")] + public string activeFlag { get; set; } + + ///// + ///// 审核标识 (1是,0否) + ///// + //[Column("audit_flag")] + //public string auditFlag { get; set; } + + /// + /// 返库标识(1是,0否) + /// + [Column("return_flag")] + public string returnFlag { get; set; } + + /// + /// 备注 + /// + [Column("remark")] + public string remark { get; set; } + + /// + /// 创建者 + /// + [Column("create_by")] + public string createBy { get; set; } + + /// + /// 创建时间 + /// + [Column("create_time")] + public DateTime? createTime { get; set; } + + /// + /// 更新者 + /// + [Column("update_by")] + public string updateBy { get; set; } + + /// + /// 更新时间 + /// + [Column("update_time")] + public DateTime? updateTime { get; set; } + + /// + /// 删除标志 1删除 0显示 + /// + [Column("del_flag")] + public string delFlag { get; set; } + + /// + /// 工厂ID + /// + [Column("factory_id")] + public long? factoryId { get; set; } + + /// + /// 数据源 + /// + [Column("data_source")] + public string dataSource { get; set; } + + /// + /// DB用户 + /// + [Column("schame")] + public string schame { get; set; } + + /// + /// 是否按照线体入库 0否 1是 + /// + [Column("line_flag")] + public string lineFlag { get; set; } + } +} + diff --git a/src/Khd.Core.Domain/Models/WmsInventoryCheck.cs b/src/Khd.Core.Domain/Models/WmsInventoryCheck.cs new file mode 100644 index 0000000..7db09e4 --- /dev/null +++ b/src/Khd.Core.Domain/Models/WmsInventoryCheck.cs @@ -0,0 +1,46 @@ +using System; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; + +namespace Khd.Core.Domain.Models +{ + [Table("wms_inventory_check")] + public class WmsInventoryCheck + { + [Key] + [Column("inventory_check_id")] + public long InventoryCheckId { get; set; } + [Column("inventory_check_code")] + public string InventoryCheckCode { get; set; } + [Column("warehouse_id")] + public long WarehouseId { get; set; } + [Column("check_status")] + public string CheckStatus { get; set; } + [Column("begin_time")] + public DateTime? BeginTime { get; set; } + [Column("end_time")] + public DateTime? EndTime { get; set; } + [Column("location_amount")] + public int LocationAmount { get; set; } + [Column("inventorying_amount")] + public int InventoryingAmount { get; set; } + [Column("inventoried_amount")] + public int InventoriedAmount { get; set; } + [Column("remark")] + public string Remark { get; set; } + [Column("create_by")] + public string CreateBy { get; set; } + [Column("create_date")] + public DateTime? CreateTime { get; set; } + [Column("update_by")] + public string UpdateBy { get; set; } + [Column("update_date")] + public DateTime? UpdateTime { get; set; } + + /// + /// 物料类型id,如果为null盘所有库,不为null盘该物料的库 + /// + [Column("material_id")] + public string? MaterialId { get; set; } + } +} diff --git a/src/Khd.Core.Domain/Models/WmsInventoryCheckDetail.cs b/src/Khd.Core.Domain/Models/WmsInventoryCheckDetail.cs new file mode 100644 index 0000000..e98dd25 --- /dev/null +++ b/src/Khd.Core.Domain/Models/WmsInventoryCheckDetail.cs @@ -0,0 +1,48 @@ +using System; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; + +namespace Khd.Core.Domain.Models +{ + [Table("wms_inventory_check_detail")] + public class WmsInventoryCheckDetail + { + [Key] + [Column("inventory_check_detail_id")] + public long InventoryCheckDetailId { get; set; } + [Column("inventory_check_id")] + public long? InventoryCheckId { get; set; } + [Column("material_id")] + public long? MaterialId { get; set; } + [Column("location_code")] + public string LocationCode { get; set; } + [Column("material_barcode")] + public string MaterialBatch { get; set; } + [Column("stock_type")] + public string StockType { get; set; } + [Column("stock_id")] + public long? StockId { get; set; } + [Column("stock_amount")] + public decimal? StockAmount { get; set; } + [Column("real_amount")] + public decimal? RealAmount { get; set; } + [Column("check_status")] + public string CheckStatus { get; set; } + [Column("inventory_time")] + public int? InventoryCount { get; set; } + [Column("erp_status")] + public string? ErpStatus { get; set; } + [Column("erp_amount")] + public decimal? ErpAmount { get; set; } + [Column("create_by")] + public string CreateBy { get; set; } + [Column("create_date")] + public DateTime? CreateTime { get; set; } + [Column("update_by")] + public string UpdateBy { get; set; } + [Column("update_date")] + public DateTime? UpdateTime { get; set; } + [Column("check_type")] + public string CheckType { get; set; } + } +} diff --git a/src/Khd.Core.Domain/Models/WmsMove.cs b/src/Khd.Core.Domain/Models/WmsMove.cs new file mode 100644 index 0000000..33bc6a4 --- /dev/null +++ b/src/Khd.Core.Domain/Models/WmsMove.cs @@ -0,0 +1,120 @@ + +//----------------------------------------------------------------------- +// +// * Copyright (C) 2021 KEHAIDASOFT All Rights Reserved +// * version : 4.0.30319.42000 +// * author : khd by t4-2 +// +//----------------------------------------------------------------------- + +using System; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; + +namespace Khd.Core.Domain.Models +{ + + [Table("wms_move")] + public class WmsMove + { + [Key] + [Column("move_id")] + public long MoveId { get; set; } + + [Required] + [Column("task_code")] + [MaxLength(128)] + public string TaskCode { get; set; } + + [Required] + [Column("warehouse_id")] + public long WarehouseId { get; set; } + + [Required] + [Column("ori_location_code")] + [MaxLength(64)] + public string OriLocationCode { get; set; } + + [Required] + [Column("target_location_code")] + [MaxLength(64)] + public string TargetLocationCode { get; set; } + + [Column("instock_batch")] + [MaxLength(64)] + public string InstockBatch { get; set; } + + [Column("material_id")] + public long? MaterialId { get; set; } + + [Column("plan_amount")] + public decimal? PlanAmount { get; set; } + + [Column("real_outstock_amount")] + public decimal RealOutstockAmount { get; set; } = 0.000000m; + + [Column("real_instock_amount")] + public decimal RealInstockAmount { get; set; } = 0.000000m; + + [Required] + [Column("operation_type")] + [MaxLength(1)] + public string OperationType { get; set; } + + [Required] + [Column("move_way")] + [MaxLength(1)] + public string MoveWay { get; set; } + + [Required] + [Column("move_type")] + [MaxLength(1)] + public string MoveType { get; set; } + + [Column("apply_reason")] + [MaxLength(500)] + public string ApplyReason { get; set; } + + [Column("audit_reason")] + [MaxLength(500)] + public string AuditReason { get; set; } + + [Required] + [Column("audit_status")] + [MaxLength(1)] + public string AuditStatus { get; set; } + + [Required] + [Column("execute_status")] + [MaxLength(1)] + public string ExecuteStatus { get; set; } + + [Column("apply_by")] + [MaxLength(64)] + public string ApplyBy { get; set; } + + [Column("apply_date")] + public DateTime? ApplyDate { get; set; } + + [Column("audit_by")] + [MaxLength(64)] + public string AuditBy { get; set; } + + [Column("audit_date")] + public DateTime? AuditDate { get; set; } + + [Column("update_by")] + [MaxLength(64)] + public string UpdateBy { get; set; } + + [Column("update_date")] + public DateTime? UpdateDate { get; set; } + + [Column("begin_time")] + public DateTime? BeginTime { get; set; } + + [Column("end_time")] + public DateTime? EndTime { get; set; } + } +} + diff --git a/src/Khd.Core.Domain/Models/WmsMoveDetail .cs b/src/Khd.Core.Domain/Models/WmsMoveDetail .cs new file mode 100644 index 0000000..4291ce8 --- /dev/null +++ b/src/Khd.Core.Domain/Models/WmsMoveDetail .cs @@ -0,0 +1,92 @@ + +//----------------------------------------------------------------------- +// +// * Copyright (C) 2021 KEHAIDASOFT All Rights Reserved +// * version : 4.0.30319.42000 +// * author : khd by t4-2 +// +//----------------------------------------------------------------------- + +using System; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; + +namespace Khd.Core.Domain.Models +{ + + [Table("wms_move_detail")] + public class WmsMoveDetail + { + [Key] + [Column("move_detail_id")] + public long MoveDetailId { get; set; } + + [Required] + [Column("move_id")] + public long MoveId { get; set; } + + [Column("material_barcode")] + [MaxLength(64)] + public string? MaterialBarcode { get; set; } + + [Column("instock_batch")] + [MaxLength(64)] + public string? InstockBatch { get; set; } + + [Required] + [Column("material_id")] + public long MaterialId { get; set; } + + [Column("location_code")] + [MaxLength(64)] + public string? LocationCode { get; set; } + + [Required] + [Column("plan_amount")] + public decimal PlanAmount { get; set; } + + [Column("real_amount")] + public decimal? RealAmount { get; set; } + + [Column("real_instock_amount")] + public decimal? RealInstockAmount { get; set; } + + [Required] + [Column("execute_status")] + [MaxLength(1)] + public string ExecuteStatus { get; set; } + + [Column("execute_person")] + [MaxLength(64)] + public string? ExecutePerson { get; set; } + + [Column("execute_time")] + public DateTime? ExecuteTime { get; set; } + + [Column("execute_end_time")] + public DateTime? ExecuteEndTime { get; set; } + + [Column("machine_name")] + [MaxLength(64)] + public string? MachineName { get; set; } + + [Column("create_by")] + [MaxLength(64)] + public string? CreateBy { get; set; } + + [Column("create_date")] + public DateTime? CreateDate { get; set; } + + [Column("update_by")] + [MaxLength(64)] + public string? UpdateBy { get; set; } + + [Column("update_date")] + public DateTime? UpdateDate { get; set; } + + [Column("active_flag")] + [MaxLength(1)] + public string? ActiveFlag { get; set; } + } +} + diff --git a/src/Khd.Core.Domain/Models/WmsProductInstock.cs b/src/Khd.Core.Domain/Models/WmsProductInstock.cs new file mode 100644 index 0000000..9ef5158 --- /dev/null +++ b/src/Khd.Core.Domain/Models/WmsProductInstock.cs @@ -0,0 +1,179 @@ + +//----------------------------------------------------------------------- +// +// * Copyright (C) 2021 KEHAIDASOFT All Rights Reserved +// * version : 4.0.30319.42000 +// * author : khd by t4-2 +// +//----------------------------------------------------------------------- + +using System; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; + +namespace Khd.Core.Domain.Models +{ + + [Table("wms_product_instock")] + public class WmsProductInstock + { + + [Key] + [Column("product_instock_id")] + public long productInstockId { get; set; } + + [Column("sale_order_id")] + public long? SaleOrderId { get; set; } + + [Column("saleorder_code")] + public string saleorderCode { get; set; } + /// + /// 任务编号 + /// + [Column("task_code")] + public string taskCode { get; set; } + + /// + /// 仓库ID + /// + [Column("warehouse_id")] + public long warehouseId { get; set; } + /// + /// 仓库ID + /// + [Column("warehouse_floor")] + public int? warehouseFloor { get; set; } + /// + /// 库位编码 + /// + [Column("location_code")] + public string locationCode { get; set; } + + /// + /// 成品类型(2半成品,3成品) + /// + [Column("product_type")] + public string productType { get; set; } + + /// + /// 操作类型(0自动,1人工,2强制,3调度);调度,适合双排库自动移库时 + /// + [Column("operation_type")] + public string operationType { get; set; } + + /// + /// 计划编号,关联pd_base_plan_info的plan_code + /// + [Column("plan_code")] + public string planCode { get; set; } + + /// + /// 计划明细编号,关联pd_base_plan_detail的plan_detail_code + /// + [Column("plan_detail_code")] + public string planDetailCode { get; set; } + + /// + /// 入库类型(1生产入库,2出半成品库,9其他入库) + /// + [Column("instock_type")] + public string instockType { get; set; } + + /// + /// 成品ID + /// + [Column("product_id")] + public long? productId { get; set; } + + /// + /// 成品批次,等于成品条码 + /// + [Column("product_batch")] + public string productBatch { get; set; } + + /// + /// 入库数量 + /// + [Column("instock_amount")] + public decimal? instockAmount { get; set; } + + /// + /// 托盘RFID代码 + /// + [Column("pallet_info_code")] + public string palletInfoCode { get; set; } + + /// + /// 申请原因 + /// + [Column("apply_reason")] + public string applyReason { get; set; } + + /// + /// 审核原因 + /// + [Column("audit_reason")] + public string auditReason { get; set; } + + /// + /// 审核状态(0待审核,1审核通过,2审核未通过) + /// + [Column("audit_status")] + public string auditStatus { get; set; } + + /// + /// 执行状态(0待执行,1执行中,2执行完成) + /// + [Column("execute_status")] + public string executeStatus { get; set; } + + /// + /// 申请人 + /// + [Column("apply_by")] + public string applyBy { get; set; } + + /// + /// 申请时间 + /// + [Column("apply_date")] + public DateTime? applyDate { get; set; } + + /// + /// 审核人 + /// + [Column("audit_by")] + public string auditBy { get; set; } + + /// + /// 审核时间 + /// + [Column("audit_date")] + public DateTime? auditDate { get; set; } + + /// + /// 最后更新人 + /// + [Column("update_by")] + public string updateBy { get; set; } + + /// + /// 最后更新时间 + /// + [Column("update_date")] + public DateTime? updateDate { get; set; } + + /// + /// 开始时间;AGV处理开始时间 + /// + [Column("begin_time")] + public DateTime? beginTime { get; set; } + + /// + /// 结束时间;agv处理结束时间 + /// + [Column("end_time")] + public DateTime? endTime { get; set; } + } +} + diff --git a/src/Khd.Core.Domain/Models/WmsProductInstockDetail.cs b/src/Khd.Core.Domain/Models/WmsProductInstockDetail.cs new file mode 100644 index 0000000..84f12c7 --- /dev/null +++ b/src/Khd.Core.Domain/Models/WmsProductInstockDetail.cs @@ -0,0 +1,116 @@ + +//----------------------------------------------------------------------- +// +// * Copyright (C) 2021 KEHAIDASOFT All Rights Reserved +// * version : 4.0.30319.42000 +// * author : khd by t4-2 +// +//----------------------------------------------------------------------- + +using System; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; + +namespace Khd.Core.Domain.Models +{ + + [Table("wms_product_instock_detail")] + public class WmsProductInstockDetail + { + + [Key] + [Column("product_instock_detail_id")] + public long? productInstockDetailId { get; set; } + + /// + /// 成品入库记录ID + /// + [Column("product_instock_id")] + public long? productInstockId { get; set; } + + /// + /// 库位编码 + /// + [Column("location_code")] + public string locationCode { get; set; } + + /// + /// 成品ID + /// + [Column("product_id")] + public long? productId { get; set; } + + /// + /// 成品条码 + /// + [Column("product_barcode")] + public string productBarcode { get; set; } + + /// + /// 成品批次 + /// + [Column("product_batch")] + public string productBatch { get; set; } + + /// + /// 执行状态(0待执行,1执行中,2执行完成) + /// + [Column("execute_status")] + public string executeStatus { get; set; } + + /// + /// 同步ERP状态(0:失败,1成功) + /// + [Column("erp_status")] + public string erpStatus { get; set; } + + /// + /// 同步给ERP的数量 + /// + [Column("erp_amount")] + public decimal? erpAmount { get; set; } + + /// + /// 计划数量 + /// + [Column("plan_amount")] + public decimal planAmount { get; set; } + + /// + /// 入库数量 + /// + [Column("instock_amount")] + public decimal? instockAmount { get; set; } + + /// + /// 入库人 + /// + [Column("instock_by")] + public string instockBy { get; set; } + + /// + /// 入库时间 + /// + [Column("instock_date")] + public DateTime? instockDate { get; set; } + + /// + /// 入库方式(1:人工入库 2:AGV入库 ) + /// + [Column("instock_way")] + public string instockWay { get; set; } + + /// + /// 最后更新人 + /// + [Column("update_by")] + public string updateBy { get; set; } + + /// + /// 最后更新时间 + /// + [Column("update_date")] + public DateTime? updateDate { get; set; } + } +} + diff --git a/src/Khd.Core.Domain/Models/WmsProductOutstock.cs b/src/Khd.Core.Domain/Models/WmsProductOutstock.cs new file mode 100644 index 0000000..079221b --- /dev/null +++ b/src/Khd.Core.Domain/Models/WmsProductOutstock.cs @@ -0,0 +1,200 @@ + +//----------------------------------------------------------------------- +// +// * Copyright (C) 2021 KEHAIDASOFT All Rights Reserved +// * version : 4.0.30319.42000 +// * author : khd by t4-2 +// +//----------------------------------------------------------------------- + +using System; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; + +namespace Khd.Core.Domain.Models +{ + + [Table("wms_product_outstock")] + public class WmsProductOutstock + { + + [Key] + [Column("product_outstock_id")] + public long productOutstockId { get; set; } + + /// + /// 任务编号 + /// + [Column("task_code")] + public string taskCode { get; set; } + + /// + /// 仓库ID;领料时需要保存 + /// + [Column("warehouse_id")] + public long warehouseId { get; set; } + + /// + /// 库位编码 + /// + [Column("location_code")] + public string locationCode { get; set; } + + /// + /// 成品类型(2半成品,3成品) + /// + [Column("product_type")] + public string productType { get; set; } + + /// + /// 操作类型(0自动,1人工,2强制,3调度) + /// + [Column("operation_type")] + public string operationType { get; set; } + + /// + /// 出库类型(1销售出库 9其他出库) + /// + [Column("outstock_type")] + public string outstockType { get; set; } + + /// + /// 计划编号,关联pd_base_plan_info的plan_code + /// + [Column("plan_code")] + public string planCode { get; set; } + + /// + /// 计划明细编号,关联pd_base_plan_detail的plan_detail_code + /// + [Column("plan_detail_code")] + public string planDetailCode { get; set; } + + /// + /// 销售订单ID主键 + /// + [Column("sale_order_id")] + public long? saleOrderId { get; set; } + + /// + /// 销售订单编号 + /// + [Column("saleorder_code")] + public string saleorderCode { get; set; } + + /// + /// 项目号 + /// + [Column("project_no")] + public string projectNo { get; set; } + + /// + /// 成品ID,关联物料信息主键 + /// + [Column("product_id")] + public long? productId { get; set; } + + /// + /// 成品批次 + /// + [Column("product_batch")] + public string productBatch { get; set; } + + /// + /// 托盘RFID代码 + /// + [Column("pallet_info_code")] + public string palletInfoCode { get; set; } + + /// + /// 出库目的地 + /// + [Column("end_station_code")] + public string endStationCode { get; set; } + + /// + /// 申请数量 + /// + [Column("apply_qty")] + public decimal? applyQty { get; set; } + + /// + /// 已出数量 + /// + [Column("outstock_qty")] + public decimal? outstockQty { get; set; } + + /// + /// 申请原因 + /// + [Column("apply_reason")] + public string applyReason { get; set; } + + /// + /// 审核原因 + /// + [Column("audit_reason")] + public string auditReason { get; set; } + + /// + /// 审核状态(0待审核,1审核通过,2审核未通过) + /// + [Column("audit_status")] + public string auditStatus { get; set; } + + /// + /// 执行状态(0待执行,1执行中,2执行完成) + /// + [Column("execute_status")] + public string executeStatus { get; set; } + + /// + /// 申请人 + /// + [Column("apply_by")] + public string applyBy { get; set; } + + /// + /// 申请时间 + /// + [Column("apply_date")] + public DateTime? applyDate { get; set; } + + /// + /// 审核人 + /// + [Column("audit_by")] + public string auditBy { get; set; } + + /// + /// 审核时间 + /// + [Column("audit_date")] + public DateTime? auditDate { get; set; } + + /// + /// 最后更新人 + /// + [Column("update_by")] + public string updateBy { get; set; } + + /// + /// 最后更新时间 + /// + [Column("update_date")] + public DateTime? updateDate { get; set; } + + /// + /// 执行开始时间 + /// + [Column("begin_time")] + public DateTime? beginTime { get; set; } + + /// + /// 执行结束时间 + /// + [Column("end_time")] + public DateTime? endTime { get; set; } + } +} + diff --git a/src/Khd.Core.Domain/Models/WmsProductOutstockDetail.cs b/src/Khd.Core.Domain/Models/WmsProductOutstockDetail.cs new file mode 100644 index 0000000..3d62cfe --- /dev/null +++ b/src/Khd.Core.Domain/Models/WmsProductOutstockDetail.cs @@ -0,0 +1,122 @@ + +//----------------------------------------------------------------------- +// +// * Copyright (C) 2021 KEHAIDASOFT All Rights Reserved +// * version : 4.0.30319.42000 +// * author : khd by t4-2 +// +//----------------------------------------------------------------------- + +using System; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; + +namespace Khd.Core.Domain.Models +{ + + [Table("wms_product_outstock_detail")] + public class WmsProductOutstockDetail + { + + [Key] + [Column("product_outstock_detail_id")] + public long productOutstockDetailId { get; set; } + + /// + /// 成品出库记录ID + /// + [Column("product_outstock_id")] + public long productOutstockId { get; set; } + + /// + /// 仓库ID + /// + [Column("warehouse_id")] + public long warehouseId { get; set; } + + /// + /// 库位编码 + /// + [Column("location_code")] + public string locationCode { get; set; } + + /// + /// 成品条码 + /// + [Column("product_barcode")] + public string productBarcode { get; set; } + + /// + /// 成品批次 + /// + [Column("product_batch")] + public string productBatch { get; set; } + + /// + /// 成品ID + /// + [Column("product_id")] + public long? productId { get; set; } + + /// + /// 计划数量 + /// + [Column("plan_amount")] + public decimal? planAmount { get; set; } + + /// + /// 出库数量 + /// + [Column("outstock_amount")] + public decimal? outstockAmount { get; set; } + + /// + /// 确认数量 + /// + [Column("confirm_amount")] + public decimal? confirmAmount { get; set; } + + /// + /// 执行状态(0待执行,1执行中,2执行完成) + /// + [Column("execute_status")] + public string executeStatus { get; set; } + + /// + /// 同步ERP状态(0:失败,1成功) + /// + [Column("erp_status")] + public string erpStatus { get; set; } + + /// + /// 同步给ERP的数量 + /// + [Column("erp_amount")] + public decimal? erpAmount { get; set; } + + /// + /// 最后更新人 + /// + [Column("update_by")] + public string updateBy { get; set; } + + /// + /// 最后更新时间 + /// + [Column("update_date")] + public DateTime? updateDate { get; set; } + + /// + /// 执行开始时间 + /// + [Column("begin_time")] + public DateTime? beginTime { get; set; } + + /// + /// 执行结束时间 + /// + [Column("end_time")] + public DateTime? endTime { get; set; } + } +} + diff --git a/src/Khd.Core.Domain/Models/WmsProductStock.cs b/src/Khd.Core.Domain/Models/WmsProductStock.cs new file mode 100644 index 0000000..379a055 --- /dev/null +++ b/src/Khd.Core.Domain/Models/WmsProductStock.cs @@ -0,0 +1,152 @@ + +//----------------------------------------------------------------------- +// +// * Copyright (C) 2021 KEHAIDASOFT All Rights Reserved +// * version : 4.0.30319.42000 +// * author : khd by t4-2 +// +//----------------------------------------------------------------------- + +using System; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; + +namespace Khd.Core.Domain.Models +{ + + [Table("wms_product_stock")] + public class WmsProductStock + { + + [Key] + [Column("product_stock_id")] + public long productStockId { get; set; } + + /// + /// 仓库ID + /// + [Column("warehouse_id")] + public long warehouseId { get; set; } + + /// + /// 仓库楼层 + /// + [Column("warehouse_floor")] + public int warehouseFloor { get; set; } + + /// + /// 库位编码 + /// + [Column("location_code")] + public string locationCode { get; set; } + + /// + /// 库存类型(2半成品,3成品) + /// + [Column("stock_type")] + public string stockType { get; set; } + + /// + /// 物料条码;在打印物料条码时,每个成品是一个条码 + /// + [Column("product_batch")] + public string productBatch { get; set; } + + /// + /// 托盘RFID代码 + /// + [Column("pallet_info_code")] + public string palletInfoCode { get; set; } + + /// + /// 质检状态(0待质检 1检验中,2质检通过,3质检不通过) + /// + [Column("quality_status")] + public string qualityStatus { get; set; } + + /// + /// 产品ID,关联物料信息的物料ID + /// + [Column("product_id")] + public long? productId { get; set; } + + /// + /// 计划编号,关联pd_base_plan_info的plan_code + /// + [Column("plan_code")] + public string planCode { get; set; } + + /// + /// 计划明细编号,关联pd_base_plan_detail的plan_detail_code + /// + [Column("plan_detail_code")] + public string planDetailCode { get; set; } + + /// + /// 销售订单ID,关联销售订单主键 + /// + [Column("sale_order_id")] + public long? saleOrderId { get; set; } + + /// + /// 销售订单编号 + /// + [Column("saleorder_code")] + public string saleorderCode { get; set; } + + /// + /// 总数量 + /// + [Column("total_amount")] + public decimal totalAmount { get; set; } + + /// + /// 冻结数量 + /// + [Column("frozen_amount")] + public decimal frozenAmount { get; set; } + + /// + /// 占用数量 + /// + [Column("occupy_amount")] + public decimal occupyAmount { get; set; } + + /// + /// 创建人 + /// + [Column("create_by")] + public string createBy { get; set; } + + /// + /// 创建时间 + /// + [Column("create_date")] + public DateTime? createDate { get; set; } + + /// + /// 最后更新人 + /// + [Column("update_by")] + public string updateBy { get; set; } + + /// + /// 最后更新时间 + /// + [Column("update_date")] + public DateTime? updateDate { get; set; } + + /// + /// 有效标记 + /// + [Column("active_flag")] + public string activeFlag { get; set; } + + /// + /// 入库时间(预留) + /// + [Column("instock_date")] + public DateTime? instockDate { get; set; } + } +} + diff --git a/src/Khd.Core.Domain/Models/WmsProductStockSaleorder.cs b/src/Khd.Core.Domain/Models/WmsProductStockSaleorder.cs new file mode 100644 index 0000000..fe73678 --- /dev/null +++ b/src/Khd.Core.Domain/Models/WmsProductStockSaleorder.cs @@ -0,0 +1,128 @@ + +//----------------------------------------------------------------------- +// +// * Copyright (C) 2021 KEHAIDASOFT All Rights Reserved +// * version : 4.0.30319.42000 +// * author : khd by t4-2 +// +//----------------------------------------------------------------------- + +using System; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; + +namespace Khd.Core.Domain.Models +{ + + [Table("wms_product_stock_saleorder")] + public class WmsProductStockSaleorder + { + + [Key] + [Column("product_stock_saleorder_id")] + public long productStockSaleorderId { get; set; } + + /// + /// 仓库ID + /// + [Column("warehouse_id")] + public long warehouseId { get; set; } + + /// + /// 仓库楼层 + /// + [Column("warehouse_floor")] + public int warehouseFloor { get; set; } + + /// + /// 库存类型(2半成品,3成品) + /// + [Column("stock_type")] + public string stockType { get; set; } + + /// + /// 产品ID,关联物料信息的物料ID + /// + [Column("product_id")] + public long productId { get; set; } + + /// + /// 销售订单ID,关联销售订单主键 + /// + [Column("sale_order_id")] + public long? saleOrderId { get; set; } + + /// + /// 销售订单编号 + /// + [Column("saleorder_code")] + public string saleorderCode { get; set; } + + /// + /// 总数量;此数量记录此订单生产的总数量,只能加,不能减 + /// + [Column("total_amount")] + public decimal totalAmount { get; set; } + + /// + /// 占用数量 + /// + [Column("occupy_amount")] + public decimal? occupyAmount { get; set; } + + /// + /// 冻结数量 + /// + [Column("frozen_amount")] + public decimal? frozenAmount { get; set; } + + /// + /// 已申请数量 + /// + [Column("apply_amount")] + public decimal? applyAmount { get; set; } + + /// + /// 已出库数量(库管或agv出库的数量) + /// + [Column("outstock_amount")] + public decimal? outstockAmount { get; set; } + + /// + /// 确认数量(在一楼最终扫码确认出库的数量) + /// + [Column("confirm_amount")] + public decimal? confirmAmount { get; set; } + + /// + /// 创建人 + /// + [Column("create_by")] + public string createBy { get; set; } + + /// + /// 创建时间 + /// + [Column("create_date")] + public DateTime? createDate { get; set; } + + /// + /// 最后更新人 + /// + [Column("update_by")] + public string updateBy { get; set; } + + /// + /// 最后更新时间 + /// + [Column("update_date")] + public DateTime? updateDate { get; set; } + + /// + /// 有效标记 + /// + [Column("active_flag")] + public string activeFlag { get; set; } + } +} + diff --git a/src/Khd.Core.Domain/Models/WmsRawInstock.cs b/src/Khd.Core.Domain/Models/WmsRawInstock.cs new file mode 100644 index 0000000..dda8529 --- /dev/null +++ b/src/Khd.Core.Domain/Models/WmsRawInstock.cs @@ -0,0 +1,183 @@ + +//----------------------------------------------------------------------- +// +// * Copyright (C) 2021 KEHAIDASOFT All Rights Reserved +// * version : 4.0.30319.42000 +// * author : khd by t4-2 +// +//----------------------------------------------------------------------- + +using System; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; + +namespace Khd.Core.Domain.Models +{ + + [Table("wms_raw_instock")] + public class WmsRawInstock + { + + [Key] + [Column("raw_instock_id")] + public long rawInstockId { get; set; } + + /// + /// 任务编号;移库时必须 + /// + [Column("task_code")] + public string taskCode { get; set; } + + /// + /// 仓库ID + /// + [Column("warehouse_id")] + public long warehouseId { get; set; } + + /// + /// 库位编码 + /// + [Column("location_code")] + public string locationCode { get; set; } + + /// + /// 采购订单号,入库扫描条码时获取唯一条码 + /// + [Column("po_no")] + public string poNo { get; set; } + + /// + /// 操作类型(0自动,1人工,2强制,3调度) + /// + [Column("operation_type")] + public string operationType { get; set; } + + /// + /// 入库类型(1采购入库,2返库入库,9其他入库) + /// + [Column("instock_type")] + public string instockType { get; set; } + + /// + /// 物料ID,关联物料信息主键 + /// + [Column("material_id")] + public long? materialId { get; set; } + + /// + /// 物料条码信息 + /// + [Column("material_barcode")] + public string materialBarCode { get; set; } + + /// + /// 物料批次信息 + /// + [Column("material_batch_code")] + public string materialBatchCode { get; set; } + + /// + /// 托盘RFID代码 + /// + [Column("pallet_info_code")] + public string palletInfoCode { get; set; } + + /// + /// 入库数量 + /// + [Column("instock_amount")] + public decimal? instockAmount { get; set; } + + ///// + ///// 申请原因 + ///// + //[Column("apply_reason")] + //public string applyReason { get; set; } + + ///// + ///// 审核原因 + ///// + //[Column("audit_reason")] + //public string auditReason { get; set; } + + ///// + ///// 审核状态(0待审核,1审核通过,2审核未通过) + ///// + //[Column("audit_status")] + //public string auditStatus { get; set; } + + /// + /// 执行状态(0待执行,1执行中,2执行完成) + /// + [Column("execute_status")] + public string executeStatus { get; set; } + + /// + /// 申请人 + /// + [Column("apply_by")] + public string applyBy { get; set; } + + /// + /// 申请时间 + /// + [Column("apply_date")] + public DateTime? applyDate { get; set; } + + ///// + ///// 审核人 + ///// + //[Column("audit_by")] + //public string auditBy { get; set; } + + ///// + ///// 审核时间 + ///// + //[Column("audit_date")] + //public DateTime? auditDate { get; set; } + + /// + /// 最后更新人 + /// + [Column("update_by")] + public string updateBy { get; set; } + + /// + /// 最后更新时间 + /// + [Column("update_date")] + public DateTime? updateDate { get; set; } + + /// + /// 开始时间 + /// + [Column("begin_time")] + public DateTime? beginTime { get; set; } + + /// + /// 结束时间 + /// + [Column("end_time")] + public DateTime? endTime { get; set; } + + /// + /// 请求返回标识(1是),execute_status改为2时此return_flag改为null + /// + [Column("return_flag")] + public string? returnFlag { get; set; } + + /// + /// 请求返回标识(1是),execute_status改为2时此return_flag改为null + /// + [Column("purchase_order_id")] + public long? purchaseOrderId { get; set; } + + /// + /// 调度CTU辅料入库人工可添加入库备注 + /// + [Column("tips")] + public string? tips { get; set; } + + } +} + diff --git a/src/Khd.Core.Domain/Models/WmsRawInstockDetail.cs b/src/Khd.Core.Domain/Models/WmsRawInstockDetail.cs new file mode 100644 index 0000000..db87a7a --- /dev/null +++ b/src/Khd.Core.Domain/Models/WmsRawInstockDetail.cs @@ -0,0 +1,176 @@ + +//----------------------------------------------------------------------- +// +// * Copyright (C) 2021 KEHAIDASOFT All Rights Reserved +// * version : 4.0.30319.42000 +// * author : khd by t4-2 +// +//----------------------------------------------------------------------- + +using System; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; + +namespace Khd.Core.Domain.Models +{ + + [Table("wms_raw_instock_detail")] + public class WmsRawInstockDetail + { + + [Key] + [Column("raw_instock_detail_id")] + public long rawInstockDetailId { get; set; } + + /// + /// 原材料入库ID + /// + [Column("raw_instock_id")] + public long rawInstockId { get; set; } + + /// + /// 原材料入库任务编号,同原材料入库记录 + /// + [Column("task_code")] + public string taskCode { get; set; } + + /// + /// 库位编码 + /// + [Column("location_code")] + public string locationCode { get; set; } + + /// + /// 存放物料条码,入库扫描条码时,从打印条码记录表中获取,关联条码信息的barcode_info + /// + [Column("material_barcode")] + public string materialBarcode { get; set; } + + /// + /// 批次;入库扫描条码时,从打印条码记录表中获取,关联条码信息的batch_code + /// + [Column("instock_batch")] + public string instockBatch { get; set; } + + /// + /// 物料ID + /// + [Column("material_id")] + public long? materialId { get; set; } + + /// + /// 采购订单号,入库扫描条码时获取唯一条码 + /// + [Column("po_no")] + public string poNo { get; set; } + + /// + /// 生产日期;入库扫描条码时,从打印条码记录表中获取 + /// + [Column("material_production_date")] + public DateTime? materialProductionDate { get; set; } + + /// + /// 计划数量 + /// + [Column("plan_amount")] + public decimal planAmount { get; set; } + + /// + /// 入库数量 + /// + [Column("instock_amount")] + public decimal? instockAmount { get; set; } + + /// + /// 执行状态(0待执行,1执行中,2执行完成) + /// + [Column("execute_status")] + public string executeStatus { get; set; } + + /// + /// 同步ERP状态(0:失败,1成功) + /// + [Column("erp_status")] + public string erpStatus { get; set; } + + /// + /// 同步给ERP的数量 + /// + [Column("erp_amount")] + public decimal? erpAmount { get; set; } + + /// + /// 入库人 + /// + [Column("instock_person")] + public string instockPerson { get; set; } + + /// + /// 入库时间 + /// + [Column("instock_time")] + public DateTime? instockTime { get; set; } + + /// + /// 入库方式(1:人工入库 2:AGV入库 ) + /// + [Column("instock_way")] + public string instockWay { get; set; } + + /// + /// 使用机台名称;入库扫描条码时,从打印条码记录表中获取 + /// + [Column("machine_name")] + public string machineName { get; set; } + + /// + /// 质检状态(0:待质检,1:合格,2:NG) + /// + [Column("quality_status")] + public string qualityStatus { get; set; } + + /// + /// 每托数量 + /// + [Column("stack_amount")] + public decimal? stackAmount { get; set; } + + /// + /// 创建人 + /// + [Column("create_by")] + public string createBy { get; set; } + + /// + /// 创建时间 + /// + [Column("create_date")] + public DateTime? createDate { get; set; } + + /// + /// 最后更新人 + /// + [Column("update_by")] + public string updateBy { get; set; } + + /// + /// 最后更新时间 + /// + [Column("update_date")] + public DateTime? updateDate { get; set; } + + /// + /// 有效标记 + /// + [Column("active_flag")] + public string activeFlag { get; set; } + + /// + /// 采购订单行项目 + /// + [Column("po_line")] + public string poLine { get; set; } + } +} + diff --git a/src/Khd.Core.Domain/Models/WmsRawOutstock.cs b/src/Khd.Core.Domain/Models/WmsRawOutstock.cs new file mode 100644 index 0000000..c9d9e84 --- /dev/null +++ b/src/Khd.Core.Domain/Models/WmsRawOutstock.cs @@ -0,0 +1,189 @@ + +//----------------------------------------------------------------------- +// +// * Copyright (C) 2021 KEHAIDASOFT All Rights Reserved +// * version : 4.0.30319.42000 +// * author : khd by t4-2 +// +//----------------------------------------------------------------------- + +using System; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; + +namespace Khd.Core.Domain.Models +{ + + [Table("wms_raw_outstock")] + public class WmsRawOutstock + { + [Column("sale_order_id")] + public long? saleOrderId { get; set; } + + [Key] + [DatabaseGenerated(DatabaseGeneratedOption.Identity)] + [Column("raw_outstock_id")] + public long? rawOutstockId { get; set; } + + /// + /// 任务编号 + /// + [Column("task_code")] + public string taskCode { get; set; } + + /// + /// 仓库ID;领料时需要保存 + /// + [Column("warehouse_id")] + public long? warehouseId { get; set; } + + /// + /// 库位编码 + /// + [Column("location_code")] + public string locationCode { get; set; } + + /// + /// 销售订单ID + /// + [Column("order_id")] + public long? orderId { get; set; } + + /// + /// 计划编号,关联mes_product_plan_info的plan_code + /// + [Column("plan_code")] + public string planCode { get; set; } + + /// + /// 计划明细编号,关联mes_product_plan_detail的plan_detail_code + /// + [Column("plan_detail_code")] + public string planDetailCode { get; set; } + + /// + /// 所属工位,关联mes_base_station_info的station_id + /// + [Column("station_id")] + public int? stationId { get; set; } + + + [Column("material_id")] + public long? materialId { get; set; } + + /// + /// 物料批次 + /// + [Column("material_batch")] + public string materialBatch { get; set; } + + /// + /// 托盘RFID代码 + /// + [Column("pallet_info_code")] + public string palletInfoCode { get; set; } + + /// + /// 计划出库数量 + /// + [Column("outstock_amount")] + public decimal outstockAmount { get; set; } + + /// + /// 已出库数量 + /// + [Column("real_outstock_amount")] + public decimal? realOutstockAmount { get; set; } + + /// + /// 出库目的地 + /// + [Column("end_station_code")] + public string endStationCode { get; set; } + + /// + /// 操作类型(0自动,1人工,2强制,3调度) + /// + [Column("operation_type")] + public string operationType { get; set; } + + /// + /// 任务类型(1生产领料,2拆分出库,3组装出库,9其他) + /// + [Column("task_type")] + public string taskType { get; set; } + + /// + /// 申请原因 + /// + [Column("apply_reason")] + public string applyReason { get; set; } + + /// + /// 审核原因 + /// + [Column("audit_reason")] + public string auditReason { get; set; } + + /// + /// 审核状态(0待审核,1审核通过,2审核未通过) + /// + [Column("audit_status")] + public string auditStatus { get; set; } + + /// + /// 执行状态(0待执行,1执行中,2执行完成) + /// + [Column("execute_status")] + public string executeStatus { get; set; } + + /// + /// 申请人 + /// + [Column("apply_by")] + public string applyBy { get; set; } + + /// + /// 申请时间 + /// + [Column("apply_date")] + public DateTime? applyDate { get; set; } + + /// + /// 审核人 + /// + [Column("audit_by")] + public string auditBy { get; set; } + + /// + /// 审核时间 + /// + [Column("audit_date")] + public DateTime? auditDate { get; set; } + + /// + /// 最后更新人 + /// + [Column("update_by")] + public string updateBy { get; set; } + + /// + /// 最后更新时间 + /// + [Column("update_date")] + public DateTime? updateDate { get; set; } + + /// + /// 执行开始时间 + /// + [Column("begin_time")] + public DateTime? beginTime { get; set; } + + /// + /// 执行结束时间 + /// + [Column("end_time")] + public DateTime? endTime { get; set; } + } +} + diff --git a/src/Khd.Core.Domain/Models/WmsRawOutstockDetail.cs b/src/Khd.Core.Domain/Models/WmsRawOutstockDetail.cs new file mode 100644 index 0000000..6bc9bb2 --- /dev/null +++ b/src/Khd.Core.Domain/Models/WmsRawOutstockDetail.cs @@ -0,0 +1,169 @@ + +//----------------------------------------------------------------------- +// +// * Copyright (C) 2021 KEHAIDASOFT All Rights Reserved +// * version : 4.0.30319.42000 +// * author : khd by t4-2 +// +//----------------------------------------------------------------------- + +using System; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; + +namespace Khd.Core.Domain.Models +{ + + [Table("wms_raw_outstock_detail")] + public class WmsRawOutstockDetail + { + + [Key] + [Column("raw_outstock_detail_id")] + public long rawOutstockDetailId { get; set; } + + /// + /// 原材料出库ID + /// + [Column("raw_outstock_id")] + public long? rawOutstockId { get; set; } + + /// + /// 原材料出库任务编号 + /// + [Column("task_code")] + public string taskCode { get; set; } + + /// + /// 仓库ID,关联仓库主键 + /// + [Column("warehouse_id")] + public long? warehouseId { get; set; } + + /// + /// 库位编码 + /// + [Column("location_code")] + public string locationCode { get; set; } + + /// + /// 物料条码;最终出库时保存 + /// + [Column("material_barcode")] + public string materialBarcode { get; set; } + + /// + /// 物料ID + /// + [Column("material_id")] + public long? materialId { get; set; } + + /// + /// 批次;扫描条码时,从打印条码记录表中获取 + /// + [Column("instock_batch")] + public string instockBatch { get; set; } + + /// + /// 生产日期;扫描条码时,从打印条码记录表中获取 + /// + [Column("material_production_date")] + public DateTime? materialProductionDate { get; set; } + + /// + /// 计划数量 + /// + [Column("plan_amount")] + public decimal planAmount { get; set; } + + /// + /// 出库数量 + /// + [Column("outstock_amount")] + public decimal? outstockAmount { get; set; } + + /// + /// 执行状态(0待执行,1执行中,2执行完成) + /// + [Column("execute_status")] + public string executeStatus { get; set; } + + /// + /// 同步ERP状态(0:失败,1成功) + /// + [Column("erp_status")] + public string erpStatus { get; set; } + + /// + /// 同步给ERP的数量 + /// + [Column("erp_amount")] + public decimal? erpAmount { get; set; } + + /// + /// 出库人 + /// + [Column("outstock_person")] + public string outstockPerson { get; set; } + + /// + /// 出库时间 + /// + [Column("outstock_time")] + public DateTime? outstockTime { get; set; } + + /// + /// 出库方式(1:人工出库 2:AGV出库 ) + /// + [Column("outstock_way")] + public string outstockWay { get; set; } + + /// + /// 使用机台名称;出库扫描条码时,从打印条码记录表中获取 + /// + [Column("machine_name")] + public string machineName { get; set; } + + /// + /// 质检状态(0:待质检,1:合格,2:NG) + /// + [Column("quality_status")] + public string qualityStatus { get; set; } + + /// + /// 创建人 + /// + [Column("create_by")] + public string createBy { get; set; } + + /// + /// 创建时间 + /// + [Column("create_date")] + public DateTime? createDate { get; set; } + + /// + /// 最后更新人 + /// + [Column("update_by")] + public string updateBy { get; set; } + /// + /// 最后更新人 + /// + [Column("tips")] + public string Tips { get; set; } + + /// + /// 最后更新时间 + /// + [Column("update_date")] + public DateTime? updateDate { get; set; } + + /// + /// 每托数量 + /// + [Column("stack_amount")] + public decimal? stackAmount { get; set; } + } +} + diff --git a/src/Khd.Core.Domain/Models/WmsRawPreferredOut.cs b/src/Khd.Core.Domain/Models/WmsRawPreferredOut.cs new file mode 100644 index 0000000..1d0cfb4 --- /dev/null +++ b/src/Khd.Core.Domain/Models/WmsRawPreferredOut.cs @@ -0,0 +1,56 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations.Schema; +using System.ComponentModel.DataAnnotations; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Khd.Core.Domain.Models +{ + [Table("wms_raw_preferred_out")] + public class WmsRawPreferredOut + { + [Key] + [Column("raw_preferred_out_id")] + public long RawPreferredOutId { get; set; } // 优先出库ID + + [Column("warehouse_id")] + public long WarehouseId { get; set; } // 仓库ID + + [Column("warehouse_floor")] + public int? WarehouseFloor { get; set; } // 仓库楼层 + + [Column("location_code")] + [Required] + [MaxLength(64)] + public string LocationCode { get; set; } // 库位编码 + + [Column("stock_type")] + [Required] + [MaxLength(1)] + public string StockType { get; set; } // 库存类型:1原材料,2成品 + + [Column("material_id")] + public long MaterialId { get; set; } // 物料ID + + [Column("create_by")] + [MaxLength(64)] + public string CreateBy { get; set; } // 创建人 + + [Column("create_date")] + public DateTime? CreateDate { get; set; } // 创建时间 + + [Column("update_by")] + [MaxLength(64)] + public string UpdateBy { get; set; } // 最后更新人 + + [Column("update_date")] + public DateTime? UpdateDate { get; set; } // 最后更新时间 + + [Column("use_flag")] + [Required] + [MaxLength(1)] + public string UseFlag { get; set; } = "1"; // 有效标记 + } +} diff --git a/src/Khd.Core.Domain/Models/WmsRawReturn.cs b/src/Khd.Core.Domain/Models/WmsRawReturn.cs new file mode 100644 index 0000000..dd10f35 --- /dev/null +++ b/src/Khd.Core.Domain/Models/WmsRawReturn.cs @@ -0,0 +1,168 @@ + +//----------------------------------------------------------------------- +// +// * Copyright (C) 2021 KEHAIDASOFT All Rights Reserved +// * version : 4.0.30319.42000 +// * author : khd by t4-2 +// +//----------------------------------------------------------------------- + +using System; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; + +namespace Khd.Core.Domain.Models +{ + + [Table("wms_raw_return")] + public class WmsRawReturn + { + + [Key] + [Column("raw_return_id")] + public long? rawReturnId { get; set; } + + /// + /// 任务编号 + /// + [Column("task_code")] + public string taskCode { get; set; } + + /// + /// 仓库ID;领料时需要保存 + /// + [Column("warehouse_id")] + public long? warehouseId { get; set; } + + /// + /// 库位编码 + /// + [Column("location_code")] + public string locationCode { get; set; } + + /// + /// 计划编号,关联mes_product_plan_info的plan_code + /// + [Column("plan_code")] + public string planCode { get; set; } + + /// + /// 计划明细编号,关联mes_product_plan_detail的plan_detail_code + /// + [Column("plan_detail_code")] + public string planDetailCode { get; set; } + + + [Column("material_id")] + public long? materialId { get; set; } + + ///// + ///// 物料批次 + ///// + //[Column("material_batch")] + //public string materialBatch { get; set; } + + /// + /// 计划出库数量 + /// + [Column("plan_amount")] + public decimal planAmount { get; set; } + + /// + /// 已出库数量 + /// + [Column("return_amount")] + public decimal returnAmount { get; set; } + + /// + /// 出库目的地 + /// + [Column("end_station_code")] + public string endStationCode { get; set; } + + /// + /// 操作类型(0自动,1人工,2强制,3调度) + /// + [Column("operation_type")] + public string operationType { get; set; } + + /// + /// 任务类型(1生产领料,2拆分出库,3组装出库,9其他) + /// + [Column("task_type")] + public string taskType { get; set; } + + /// + /// 申请原因 + /// + [Column("apply_reason")] + public string applyReason { get; set; } + + /// + /// 审核原因 + /// + [Column("audit_reason")] + public string auditReason { get; set; } + + /// + /// 审核状态(0待审核,1审核通过,2审核未通过) + /// + [Column("audit_status")] + public string auditStatus { get; set; } + + /// + /// 执行状态(0待执行,1执行中,2执行完成) + /// + [Column("execute_status")] + public string executeStatus { get; set; } + + /// + /// 申请人 + /// + [Column("apply_by")] + public string applyBy { get; set; } + + /// + /// 申请时间 + /// + [Column("apply_date")] + public DateTime? applyDate { get; set; } + + /// + /// 审核人 + /// + [Column("audit_by")] + public string auditBy { get; set; } + + /// + /// 审核时间 + /// + [Column("audit_date")] + public DateTime? auditDate { get; set; } + + /// + /// 最后更新人 + /// + [Column("update_by")] + public string updateBy { get; set; } + + /// + /// 最后更新时间 + /// + [Column("update_date")] + public DateTime? updateDate { get; set; } + + /// + /// 执行开始时间 + /// + [Column("begin_time")] + public DateTime? beginTime { get; set; } + + /// + /// 执行结束时间 + /// + [Column("end_time")] + public DateTime? endTime { get; set; } + } +} + diff --git a/src/Khd.Core.Domain/Models/WmsRawReturnDetail.cs b/src/Khd.Core.Domain/Models/WmsRawReturnDetail.cs new file mode 100644 index 0000000..ca0792a --- /dev/null +++ b/src/Khd.Core.Domain/Models/WmsRawReturnDetail.cs @@ -0,0 +1,104 @@ + +//----------------------------------------------------------------------- +// +// * Copyright (C) 2021 KEHAIDASOFT All Rights Reserved +// * version : 4.0.30319.42000 +// * author : khd by t4-2 +// +//----------------------------------------------------------------------- + +using Microsoft.EntityFrameworkCore; +using System; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; + +namespace Khd.Core.Domain.Models +{ + + [Table("wms_raw_return_detail")] + public class WmsRawReturnDetail + { + [Key] + [Column("raw_return_detail_id")] + public long RawReturnDetailId { get; set; } + + [Column("raw_return_id")] + public long RawReturnId { get; set; } + + [Column("location_code")] + [StringLength(64)] + public string LocationCode { get; set; } + + [Column("material_barcode")] + [StringLength(64)] + public string MaterialBarcode { get; set; } + + [Column("material_id")] + public long MaterialId { get; set; } + + [Column("instock_batch")] + [StringLength(64)] + public string InstockBatch { get; set; } + + [Column("material_production_date")] + public DateTime? MaterialProductionDate { get; set; } + + [Column("plan_amount")] + [Precision(16, 2)] + public decimal PlanAmount { get; set; } + + [Column("return_amount")] + [Precision(16, 2)] + public decimal? ReturnAmount { get; set; } + + [Column("execute_status")] + [StringLength(1)] + public string ExecuteStatus { get; set; } + + [Column("erp_status")] + [StringLength(1)] + public string ErpStatus { get; set; } + + [Column("erp_amount")] + [Precision(16, 2)] + public decimal? ErpAmount { get; set; } + + [Column("return_person")] + [StringLength(64)] + public string ReturnPerson { get; set; } + + [Column("return_time")] + public DateTime? ReturnTime { get; set; } + + [Column("return_way")] + [StringLength(1)] + public string ReturnWay { get; set; } + + [Column("machine_name")] + [StringLength(64)] + public string MachineName { get; set; } + + [Column("quality_status")] + [StringLength(1)] + public string QualityStatus { get; set; } + + [Column("create_by")] + [StringLength(64)] + public string CreateBy { get; set; } + + [Column("create_date")] + public DateTime? CreateDate { get; set; } + + [Column("update_by")] + [StringLength(64)] + public string UpdateBy { get; set; } + + [Column("update_date")] + public DateTime? UpdateDate { get; set; } + + [Column("stack_amount")] + [Precision(16, 2)] + public decimal? StackAmount { get; set; } + } +} + diff --git a/src/Khd.Core.Domain/Models/WmsRawStock.cs b/src/Khd.Core.Domain/Models/WmsRawStock.cs new file mode 100644 index 0000000..5b48cdf --- /dev/null +++ b/src/Khd.Core.Domain/Models/WmsRawStock.cs @@ -0,0 +1,150 @@ + +//----------------------------------------------------------------------- +// +// * Copyright (C) 2021 KEHAIDASOFT All Rights Reserved +// * version : 4.0.30319.42000 +// * author : khd by t4-2 +// +//----------------------------------------------------------------------- + +using System; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; + +namespace Khd.Core.Domain.Models +{ + + [Table("wms_raw_stock")] + public class WmsRawStock + { + + [Key] + [Column("raw_stock_id")] + public long rawStockId { get; set; } + + /// + /// 仓库ID + /// + [Column("warehouse_id")] + public long warehouseId { get; set; } + + /// + /// 仓库楼层 + /// + [Column("warehouse_floor")] + public int? warehouseFloor { get; set; } + + /// + /// 库位编码 + /// + [Column("location_code")] + public string locationCode { get; set; } + + /// + /// 库存类型:1原材料 2半成品 + /// + [Column("stock_type")] + public string stockType { get; set; } + + /// + /// 物料ID + /// + [Column("material_id")] + public long? materialId { get; set; } + + /// + /// 入库批次号 + /// + [Column("instock_batch")] + public string instockBatch { get; set; } + + /// + /// 托盘RFID代码 + /// + [Column("pallet_info_code")] + public string palletInfoCode { get; set; } + + /// + /// 入库时间;此入库时间从批次信息中获取,accepted_date + /// + [Column("instock_date")] + public DateTime? instockDate { get; set; } + + /// + /// 最晚出库时间;入库时,根据物料信“存放周期“计算出来的时间 + /// + [Column("last_outstock_time")] + public DateTime? lastOutstockTime { get; set; } + + /// + /// 质检状态(0待质检,1检验中,2质检通过,3质检不通过) + /// + [Column("quality_status")] + public string qualityStatus { get; set; } + + /// + /// 完整标识(1是0否)拆分后为0 + /// + [Column("complete_flag")] + public string completeFlag { get; set; } + + /// + /// 总数量;库位存放的总数量 + /// + [Column("total_amount")] + public decimal? totalAmount { get; set; } + + /// + /// 冻结数量;手动冻结的,暂时可不用 + /// + [Column("frozen_amount")] + public decimal? frozenAmount { get; set; } + + /// + /// 占用数量;申请时占用的数量,在出库时要减去出库数量,并且总数量要同步更新; + /// + [Column("occupy_amount")] + public decimal? occupyAmount { get; set; } + + /// + /// 供应商ID + /// + [Column("supplier_id")] + public long? supplierId { get; set; } + + /// + /// 创建人 + /// + [Column("create_by")] + public string createBy { get; set; } + [Column("safe_flag")] + public string safeFlag { get; set; } + /// + /// 创建时间 + /// + [Column("create_date")] + public DateTime? createDate { get; set; } + + /// + /// 最后更新人 + /// + [Column("update_by")] + public string updateBy { get; set; } + + /// + /// 最后更新时间 + /// + [Column("update_date")] + public DateTime? updateDate { get; set; } + + /// + /// 有效标记 + /// + [Column("active_flag")] + public string activeFlag { get; set; } + + [Column("sale_order_id")] + public long? saleOrderId { get; set; } + } +} + diff --git a/src/Khd.Core.Domain/Models/WmsRawStockOccupy.cs b/src/Khd.Core.Domain/Models/WmsRawStockOccupy.cs new file mode 100644 index 0000000..8ae2add --- /dev/null +++ b/src/Khd.Core.Domain/Models/WmsRawStockOccupy.cs @@ -0,0 +1,93 @@ + +//----------------------------------------------------------------------- +// +// * Copyright (C) 2021 KEHAIDASOFT All Rights Reserved +// * version : 4.0.30319.42000 +// * author : khd by t4-2 +// +//----------------------------------------------------------------------- + +using System; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; + +namespace Khd.Core.Domain.Models +{ + + [Table("wms_raw_stock_occupy")] + public class WmsRawStockOccupy + { + + [Key] + [Column("raw_stock_occupy_id")] + public long rawStockOccupyId { get; set; } + + /// + /// 仓库ID + /// + [Column("warehouse_id")] + public long warehouseId { get; set; } + + /// + /// 库位编码 + /// + [Column("location_code")] + public string locationCode { get; set; } + + /// + /// 库存类型:1原材料 2半成品 + /// + [Column("stock_type")] + public string stockType { get; set; } + + /// + /// 物料ID + /// + [Column("material_id")] + public long materialId { get; set; } + + /// + /// 占用数量;申请时占用的数量,在出库时要减去出库数量,并且总数量要同步更新; + //或者在柜体拆分后返库后占用的数量,在组装时需要匹配出库 + /// + [Column("occupy_amount")] + public decimal? occupyAmount { get; set; } + + /// + /// 占用类型(1生产工单,2申请领料) + /// + [Column("occupy_type")] + public string occupyType { get; set; } + + /// + /// 根据占用类型关联占用的主键ID + /// + [Column("occupy_id")] + public long? occupyId { get; set; } + + /// + /// 创建人 + /// + [Column("create_by")] + public string createBy { get; set; } + + /// + /// 创建时间 + /// + [Column("create_time")] + public DateTime? createTime { get; set; } + + /// + /// 最后更新人 + /// + [Column("update_by")] + public string updateBy { get; set; } + + /// + /// 最后更新时间 + /// + [Column("update_time")] + public DateTime? updateTime { get; set; } + } +} + diff --git a/src/Khd.Core.Domain/Models/WmsWarehouseMaterial.cs b/src/Khd.Core.Domain/Models/WmsWarehouseMaterial.cs new file mode 100644 index 0000000..8a4c4c0 --- /dev/null +++ b/src/Khd.Core.Domain/Models/WmsWarehouseMaterial.cs @@ -0,0 +1,62 @@ + +//----------------------------------------------------------------------- +// +// * Copyright (C) 2021 KEHAIDASOFT All Rights Reserved +// * version : 4.0.30319.42000 +// * author : khd by t4-2 +// +//----------------------------------------------------------------------- + +using System; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; + +namespace Khd.Core.Domain.Models +{ + + [Table("wms_warehouse_material")] + public class WmsWarehouseMaterial + { + + [Key] + [Column("warehouse_material_id")] + public long warehouseMaterialId { get; set; } + + /// + /// 仓库ID + /// + [Column("warehouse_id")] + public long warehouseId { get; set; } + + /// + /// 库位编码;单独需要针对库位设置的,后续扩展使用 + /// + [Column("location_code")] + public string locationCode { get; set; } + + /// + /// 存储类型(1、物料,2、物料类型);先支持物料 + /// + [Column("storage_type")] + public string storageType { get; set; } + + /// + /// 根据存储类型对应各自表的主键 + /// + [Column("storage_id")] + public long storageId { get; set; } + + /// + /// 创建时间 + /// + [Column("create_time")] + public DateTime? createTime { get; set; } + + /// + /// 创建人 + /// + [Column("create_by")] + public string createBy { get; set; } + } +} + diff --git a/src/Khd.Core.EntityFramework/DbContextExtensions.cs b/src/Khd.Core.EntityFramework/DbContextExtensions.cs new file mode 100644 index 0000000..1a61567 --- /dev/null +++ b/src/Khd.Core.EntityFramework/DbContextExtensions.cs @@ -0,0 +1,77 @@ +using Microsoft.EntityFrameworkCore; +using System; +using System.Collections.Generic; +using System.Data; +using System.Linq; + +namespace Khd.Core.EntityFramework +{ + public static class DbContextExtensions + { + //public static List ExecuteSqlQuery(this DbContext dbContext, string sqlQuery) where T : class + //{ + // using var command = dbContext.Database.GetDbConnection().CreateCommand(); + // command.CommandText = sqlQuery; + // command.CommandType = CommandType.Text; + + // dbContext.Database.OpenConnection(); + + // using var reader = command.ExecuteReader(); + // var result = new List(); + + // while (reader.Read()) + // { + // var entity = Activator.CreateInstance(); + // foreach (var prop in typeof(T).GetProperties()) + // { + // var value = reader[prop.Name]; + // if (value != DBNull.Value) + // { + // prop.SetValue(entity, value); + // } + // } + // result.Add(entity); + // } + + // return result; + //} + + public static List ExecuteSqlQuery(this DbContext dbContext, string sqlQuery) where T : class, new() + { + using var command = dbContext.Database.GetDbConnection().CreateCommand(); + command.CommandText = sqlQuery; + command.CommandType = CommandType.Text; + + dbContext.Database.OpenConnection(); + + using var reader = command.ExecuteReader(); + var result = new List(); + + var columnNames = Enumerable.Range(0, reader.FieldCount).Select(reader.GetName).ToList(); + + while (reader.Read()) + { + var entity = new T(); + var properties = typeof(T).GetProperties(); + + foreach (var prop in properties) + { + var propName = prop.Name; + if (!columnNames.Contains(propName)) + continue; + + var value = reader[propName]; + if (value != DBNull.Value) + { + prop.SetValue(entity, value); + } + } + + result.Add(entity); + } + + return result; + } + } + +} diff --git a/src/Khd.Core.EntityFramework/DefaultDbContext.cs b/src/Khd.Core.EntityFramework/DefaultDbContext.cs new file mode 100644 index 0000000..fd1ec7a --- /dev/null +++ b/src/Khd.Core.EntityFramework/DefaultDbContext.cs @@ -0,0 +1,101 @@ +using Khd.Core.Domain.Auth; +using Khd.Core.Domain.Dto.agv; +using Khd.Core.Domain.Models; +using Microsoft.EntityFrameworkCore; + +namespace Khd.Core.EntityFramework +{ + public class DefaultDbContext : DbContext + { + public DefaultDbContext(DbContextOptions options) : base(options) + { + } + + public DbSet SysUser { get; set; } + public DbSet SysRole { get; set; } + public DbSet SysMenu { get; set; } + public DbSet WcsAgvStatus { get; set; } + public DbSet WmsInventoryCheck { get; set; } + public DbSet WmsInventoryCheckDetail { get; set; } + public DbSet MesBaseMaterialInfo { get; set; } + public DbSet WmsRawReturn { get; set; } + public DbSet WmsRawPreferredOut { get; set; } + public DbSet WmsMove { get; set; } + public DbSet WmsMoveDetail { get; set; } + public DbSet WmsRawReturnDetail { get; set; } + public DbSet WcsTaskManual { get; set; } + public DbSet BaseDictionary { get; set; } + + public DbSet BaseEquip { get; set; } + + public DbSet BasePlcpoint { get; set; } + + public DbSet BasePlc { get; set; } + + public DbSet MesBasePalletInfo { get; set; } + + public DbSet MesSaleOrderRelate { get; set; } + + public DbSet MesProductPlanDetail { get; set; } + + public DbSet WcsCmd { get; set; } + + public DbSet WcsCmdLog { get; set; } + + public DbSet WcsStock { get; set; } + + public DbSet WcsTask { get; set; } + + public DbSet WcsTaskLog { get; set; } + + public DbSet WcsWarehouseOrder { get; set; } + + public DbSet WcsWarehouseOrderDetaile { get; set; } + + public DbSet WmsBaseLocation { get; set; } + + public DbSet WmsBaseWarehouse { get; set; } + + public DbSet WmsProductInstock { get; set; } + + public DbSet WmsProductInstockDetail { get; set; } + + public DbSet WmsProductOutstock { get; set; } + + public DbSet WmsProductOutstockDetail { get; set; } + + public DbSet WmsProductStock { get; set; } + + public DbSet WmsProductStockSaleorder { get; set; } + + public DbSet WmsRawInstock { get; set; } + + public DbSet WmsRawInstockDetail { get; set; } + + public DbSet WmsRawOutstock { get; set; } + + public DbSet WmsRawOutstockDetail { get; set; } + + public DbSet WmsRawStock { get; set; } + + public DbSet WmsRawStockOccupy { get; set; } + + public DbSet WmsWarehouseMaterial { get; set; } + + public DbSet WcsOutstockLock { get; set; } + + public DbSet MesBaseBarcodeInfo { get; set; } + + public DbSet PlcPoint { get; set; } + + public DbSet DmsBaseAlarmRule { get; set; } + + public DbSet DmsBaseDeviceLedger { get; set; } + + public DbSet DmsRecordAlarmInfo { get; set; } + + public DbSet DmsRecordAlarmTime { get; set; } + + public DbSet MesBaseUnitInfo { get; set; } + } +} \ No newline at end of file diff --git a/src/Khd.Core.EntityFramework/Khd.Core.EntityFramework.csproj b/src/Khd.Core.EntityFramework/Khd.Core.EntityFramework.csproj new file mode 100644 index 0000000..46dbf9f --- /dev/null +++ b/src/Khd.Core.EntityFramework/Khd.Core.EntityFramework.csproj @@ -0,0 +1,23 @@ + + + + net6.0 + + + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + + + + + + + diff --git a/src/Khd.Core.Library/Attributes/NotWarpApiResultAttribute.cs b/src/Khd.Core.Library/Attributes/NotWarpApiResultAttribute.cs new file mode 100644 index 0000000..ff8d095 --- /dev/null +++ b/src/Khd.Core.Library/Attributes/NotWarpApiResultAttribute.cs @@ -0,0 +1,9 @@ +using System; + +namespace Khd.Core.Library.Attributes +{ + [AttributeUsage(AttributeTargets.Method)] + public class NotWarpApiResultAttribute : Attribute + { + } +} \ No newline at end of file diff --git a/src/Khd.Core.Library/Dto/ApiResult.cs b/src/Khd.Core.Library/Dto/ApiResult.cs new file mode 100644 index 0000000..f18c5ed --- /dev/null +++ b/src/Khd.Core.Library/Dto/ApiResult.cs @@ -0,0 +1,72 @@ +namespace Khd.Core.Library.Dto +{ + public sealed class ApiResult : ApiResult + { + public ApiResult(int errorCode, string message, TResult result) + : base(errorCode, message) + { + Result = result; + } + + public TResult Result { get; set; } + + public void SetSuccess(TResult data) + { + IsSuccess = true; + Result = data; + } + + public ApiResult SetApiResult(TResult data) + { + Result = data; + return this; + } + } + + public class ApiResult + { + public ApiResult(int errorCode, string message) + { + ErrorCode = errorCode; + Message = message; + } + + public bool IsSuccess { get; set; } + + public int ErrorCode { get; set; } + + public string Message { get; set; } + + public string OperationId { get; set; } + + public void SetSuccess() + { + IsSuccess = true; + } + + public void SetFailed(int errorCode) + { + IsSuccess = false; + ErrorCode = errorCode; + } + + public void SetFailed(string msg) + { + IsSuccess = false; + ErrorCode = -1; + Message = msg; + } + + public void SetFailed(int errorCode, string msg) + { + IsSuccess = false; + ErrorCode = errorCode; + Message = msg; + } + + public override string ToString() + { + return $"{IsSuccess},ErrorCode:{ErrorCode},Message:{Message}"; + } + } +} \ No newline at end of file diff --git a/src/Khd.Core.Library/EntityFrameworkCore/BaseDbContext.cs b/src/Khd.Core.Library/EntityFrameworkCore/BaseDbContext.cs new file mode 100644 index 0000000..11f1333 --- /dev/null +++ b/src/Khd.Core.Library/EntityFrameworkCore/BaseDbContext.cs @@ -0,0 +1,34 @@ +using Microsoft.EntityFrameworkCore; +using System.Threading; +using System.Threading.Tasks; + +namespace Khd.Core.Library.EntityFrameworkCore +{ + public class BaseDbContext : DbContext + { + public override int SaveChanges() + { + return base.SaveChanges(); + } + + public override int SaveChanges(bool acceptAllChangesOnSuccess) + { + return base.SaveChanges(acceptAllChangesOnSuccess); + } + + public override Task SaveChangesAsync(CancellationToken cancellationToken = new CancellationToken()) + { + return base.SaveChangesAsync(cancellationToken); + } + + public override Task SaveChangesAsync(bool acceptAllChangesOnSuccess, CancellationToken cancellationToken = new CancellationToken()) + { + return base.SaveChangesAsync(acceptAllChangesOnSuccess, cancellationToken); + } + + private void ApplyConcepts() + { + + } + } +} diff --git a/src/Khd.Core.Library/EntityFrameworkCore/Entity.cs b/src/Khd.Core.Library/EntityFrameworkCore/Entity.cs new file mode 100644 index 0000000..c5b25af --- /dev/null +++ b/src/Khd.Core.Library/EntityFrameworkCore/Entity.cs @@ -0,0 +1,14 @@ +using System.ComponentModel.DataAnnotations; +using System.Text.Json.Serialization; + +namespace Khd.Core.Library.EntityFrameworkCore +{ + public class Entity : ISoftDelete + { + [Key] + public int Id { get; set; } + + [JsonIgnore] + public bool IsDeleted { get; set; } + } +} \ No newline at end of file diff --git a/src/Khd.Core.Library/EntityFrameworkCore/ISoftDelete.cs b/src/Khd.Core.Library/EntityFrameworkCore/ISoftDelete.cs new file mode 100644 index 0000000..dd210d3 --- /dev/null +++ b/src/Khd.Core.Library/EntityFrameworkCore/ISoftDelete.cs @@ -0,0 +1,7 @@ +namespace Khd.Core.Library.EntityFrameworkCore +{ + public interface ISoftDelete + { + public bool IsDeleted { get; set; } + } +} diff --git a/src/Khd.Core.Library/Exception/ResponseExceptionBase.cs b/src/Khd.Core.Library/Exception/ResponseExceptionBase.cs new file mode 100644 index 0000000..01cca23 --- /dev/null +++ b/src/Khd.Core.Library/Exception/ResponseExceptionBase.cs @@ -0,0 +1,7 @@ +namespace Khd.Core.Library.Exception +{ + public abstract class ResponseExceptionBase : System.Exception + { + public int ErrorCode { get; protected set; } + } +} \ No newline at end of file diff --git a/src/Khd.Core.Library/Exception/StringResponseException.cs b/src/Khd.Core.Library/Exception/StringResponseException.cs new file mode 100644 index 0000000..e172ae3 --- /dev/null +++ b/src/Khd.Core.Library/Exception/StringResponseException.cs @@ -0,0 +1,18 @@ +namespace Khd.Core.Library.Exception +{ + public class StringResponseException : ResponseExceptionBase + { + public StringResponseException(int errorCode, string errorMessage) + { + ErrorCode = errorCode; + Message = errorMessage; + } + + public StringResponseException(string errorMessage) + : this(0, errorMessage) + { + } + + public override string Message { get; } + } +} \ No newline at end of file diff --git a/src/Khd.Core.Library/Extensions/NetworkHelper.cs b/src/Khd.Core.Library/Extensions/NetworkHelper.cs new file mode 100644 index 0000000..907c6e9 --- /dev/null +++ b/src/Khd.Core.Library/Extensions/NetworkHelper.cs @@ -0,0 +1,72 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Net.NetworkInformation; +using System.Net.Sockets; +using System.Text; +using System.Threading.Tasks; + +namespace Khd.Core.Library.Extensions +{ + public class NetworkHelper + { + /// + /// 获取本地计算机的所有 IPv4 地址。 + /// + /// IPv4 地址列表。如果没有找到,则返回一个空列表。 + public static List GetLocalIPv4Addresses() + { + List ipAddresses = new List(); + + try + { + // 获取所有网络接口 + var networkInterfaces = NetworkInterface.GetAllNetworkInterfaces(); + + foreach (var networkInterface in networkInterfaces) + { + // 检查网络接口是否处于正常状态且不是回环接口 + if (networkInterface.OperationalStatus == OperationalStatus.Up && + networkInterface.NetworkInterfaceType != NetworkInterfaceType.Loopback) + { + // 获取该接口的IP属性 + var ipProperties = networkInterface.GetIPProperties(); + + // 获取单播地址集合 + var unicastAddresses = ipProperties.UnicastAddresses; + + foreach (var address in unicastAddresses) + { + // 检查是否是 IPv4 地址 + if (address.Address.AddressFamily == AddressFamily.InterNetwork) + { + // 获取 IPv4 地址并添加到列表 + var ipAddress = address.Address.ToString(); + if (!string.IsNullOrEmpty(ipAddress) && !ipAddress.StartsWith("169.254")) // 排除自动私有地址 + { + ipAddresses.Add(ipAddress); + } + } + } + } + } + } + catch + { + Console.WriteLine("获取IP地址时发生错误"); + } + + return ipAddresses; + } + + /// + /// 获取本地计算机的第一个有效的 IPv4 地址。 + /// + /// 第一个有效的 IPv4 地址,如果没有找到则返回 null。 + public static string GetFirstLocalIPv4Address() + { + var ipAddresses = GetLocalIPv4Addresses(); + return ipAddresses.Count > 0 ? ipAddresses[0] : null; + } + } +} diff --git a/src/Khd.Core.Library/Extensions/StringExtensions.cs b/src/Khd.Core.Library/Extensions/StringExtensions.cs new file mode 100644 index 0000000..edf2cb7 --- /dev/null +++ b/src/Khd.Core.Library/Extensions/StringExtensions.cs @@ -0,0 +1,19 @@ +using System.Security.Cryptography; +using System.Text; + +namespace Khd.Core.Library.Extensions +{ + public static class StringExtensions + { + public static string GetMd5(this string value) + { + using var md5Hash = MD5.Create(); + var data = md5Hash.ComputeHash(Encoding.UTF8.GetBytes(value)); + var sBuilder = new StringBuilder(); + foreach (var b in data) sBuilder.Append(b.ToString("x2")); + + var hash = sBuilder.ToString(); + return hash; + } + } +} \ No newline at end of file diff --git a/src/Khd.Core.Library/Filter/ExceptionFilter.cs b/src/Khd.Core.Library/Filter/ExceptionFilter.cs new file mode 100644 index 0000000..68836c3 --- /dev/null +++ b/src/Khd.Core.Library/Filter/ExceptionFilter.cs @@ -0,0 +1,72 @@ +using Khd.Core.Library.Dto; +using Khd.Core.Library.Exception; +using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Mvc.Filters; +using Microsoft.Extensions.Logging; +using System; +using System.Linq; +using System.Net; +using System.Text.Encodings.Web; +using System.Text.Json; + +namespace Khd.Core.Library.Filter +{ + public class ExceptionFilter : IExceptionFilter + { + private static readonly JsonSerializerOptions JsonSerializerSettings = new JsonSerializerOptions + { + PropertyNamingPolicy = JsonNamingPolicy.CamelCase, + Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping + }; + + private readonly ILogger _logger; + + /// + /// 异常处理过滤器 + /// + public ExceptionFilter(ILogger logger) + { + _logger = logger; + } + + public void OnException(ExceptionContext context) + { + System.Exception ex; + if (context.Exception is AggregateException) + ex = ((AggregateException)context.Exception).InnerExceptions.First(); + else + ex = context.Exception; + + if (ex is ResponseExceptionBase rEx) ProcessBusinessException(rEx, context); + } + + /// + /// 业务异常的处理 + /// + /// + /// + private void ProcessBusinessException(ResponseExceptionBase ex, ExceptionContext context) + { + const HttpStatusCode statusCode = (HttpStatusCode)288; + + string exMessage; + int errorCode; + + if (ex is StringResponseException) + { + errorCode = ex.ErrorCode == 0 ? int.MaxValue : ex.ErrorCode; + exMessage = ex.Message; + } + else + { + errorCode = ex.ErrorCode; + //var message = _enumDescriptionService.GetDescriptionValue(ex.ErrorCode); + exMessage = string.Empty; + } + + context.HttpContext.Response.StatusCode = (int)statusCode; + _logger.LogInformation(errorCode, "发生业务异常 {0} {1}", errorCode.ToString(), exMessage); + context.Result = new JsonResult(new ApiResult(errorCode, exMessage), JsonSerializerSettings); + } + } +} \ No newline at end of file diff --git a/src/Khd.Core.Library/Filter/ResultFilter.cs b/src/Khd.Core.Library/Filter/ResultFilter.cs new file mode 100644 index 0000000..13e057a --- /dev/null +++ b/src/Khd.Core.Library/Filter/ResultFilter.cs @@ -0,0 +1,49 @@ +using Khd.Core.Library.Attributes; +using Khd.Core.Library.Dto; +using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Mvc.Controllers; +using Microsoft.AspNetCore.Mvc.Filters; +using System.Diagnostics; + +namespace Khd.Core.Library.Filter +{ + public class ResultFilter : IResultFilter + { + public void OnResultExecuting(ResultExecutingContext context) + { + var notWarpApiResultAttribute = + (context.ActionDescriptor as ControllerActionDescriptor)?.MethodInfo?.IsDefined( + typeof(NotWarpApiResultAttribute), false) ?? false; + if (notWarpApiResultAttribute) + return; + + var or = context.Result as ObjectResult; + if (or == null || or.Value is ApiResult) + { + if (context.Result is EmptyResult) + { + var emptyResult = new ApiResult(0, string.Empty); + if (Activity.Current != null) + emptyResult.OperationId = Activity.Current.Id; + emptyResult.SetSuccess(); + context.Result = new OkObjectResult(emptyResult); + return; + } + + return; + } + + var response = new ApiResult(or.StatusCode ?? 0, string.Empty, or.Value); + response.SetSuccess(); + if (Activity.Current != null) + response.OperationId = Activity.Current.Id; + or.DeclaredType = typeof(ApiResult<>); + or.Value = response; + } + + public void OnResultExecuted(ResultExecutedContext context) + { + //Nothing + } + } +} \ No newline at end of file diff --git a/src/Khd.Core.Library/Khd.Core.Library.csproj b/src/Khd.Core.Library/Khd.Core.Library.csproj new file mode 100644 index 0000000..6db1aca --- /dev/null +++ b/src/Khd.Core.Library/Khd.Core.Library.csproj @@ -0,0 +1,16 @@ + + + + net6.0 + + + + + + + + + + + + \ No newline at end of file diff --git a/src/Khd.Core.Library/LibraryExtensions.cs b/src/Khd.Core.Library/LibraryExtensions.cs new file mode 100644 index 0000000..f17c7c6 --- /dev/null +++ b/src/Khd.Core.Library/LibraryExtensions.cs @@ -0,0 +1,24 @@ +using Khd.Core.Library.Filter; +using Khd.Core.Library.Swagger; +using Microsoft.Extensions.DependencyInjection; + +namespace Khd.Core.Library +{ + public static class LibraryExtensions + { + public static void AddLibrary(this IServiceCollection services) + { + services.AddControllers(options => + { + //可以定义出参格式 + //options.Filters.Add(); + options.Filters.Add(); + }); + services.AddMvc().AddJsonOptions(option => + { + option.JsonSerializerOptions.IgnoreNullValues = true; + }); + services.AddLibrarySwagger(); + } + } +} \ No newline at end of file diff --git a/src/Khd.Core.Library/LoggerUtils.cs b/src/Khd.Core.Library/LoggerUtils.cs new file mode 100644 index 0000000..306d9f3 --- /dev/null +++ b/src/Khd.Core.Library/LoggerUtils.cs @@ -0,0 +1,57 @@ +using System; + +namespace Khd.Core.Library +{ + public class LoggerUtils : IDisposable + { + + NLog.Logger logger = NLog.LogManager.GetLogger("LoggerFile"); + public LoggerUtils() + { + + } + + /// + /// 信息记录 + /// + /// + public void Log(string msg) + { + logger.Info(msg); + } + + /// + /// 信息记录 + /// + /// + public void Info(string msg) + { + logger.Info(msg); + } + /// + /// 错误记录 + /// + /// + public void Error(string msg) + { + logger.Error(msg); + } + + public void Close() + { + + } + + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(true); + } + + protected virtual void Dispose(bool disposing) + { + if (!disposing) + return; + } + } +} diff --git a/src/Khd.Core.Library/Mapper/CoreMapper.cs b/src/Khd.Core.Library/Mapper/CoreMapper.cs new file mode 100644 index 0000000..4f8c121 --- /dev/null +++ b/src/Khd.Core.Library/Mapper/CoreMapper.cs @@ -0,0 +1,38 @@ +using Mapster; +using System; + +namespace Khd.Core.Library.Mapper +{ + public class CoreMapper + { + /// + /// Map source object to destination object + /// + /// The type of the destination. + /// The source object. + /// The destination object. + /// Thrown when source is null. + public static TDestination Map(object source) + { + if (source == null) + throw new ArgumentNullException("Map Error : source is null"); + TypeAdapterConfig config = new TypeAdapterConfig(); + + config.NewConfig().MapWith(dest => string.IsNullOrEmpty(dest.Trim()) ? Guid.Empty : new Guid(dest)); + config.NewConfig().MapWith(dest => string.IsNullOrEmpty(dest.Trim()) ? null : new Guid(dest)); + config.NewConfig().MapWith(dest => dest.ToString()); + + config.NewConfig().MapWith(dest => string.IsNullOrEmpty(dest) ? DateTime.Now : Convert.ToDateTime(dest)); + config.NewConfig().MapWith(dest => string.IsNullOrEmpty(dest) ? null : Convert.ToDateTime(dest)); + config.NewConfig().MapWith(dest => dest.ToString()); + // var c = source.Adapt(destination, config2); + config.NewConfig().MapWith(dest => dest.Trim()); + // config.ForType().Map(member: guid => guid, source: @string => string.IsNullOrEmpty(@string) ? Guid.Empty : new Guid(@string)); + // config.ForType().Map(member: @string => @string, source: guid => ("wode")); + config.Default.IgnoreNullValues(true);//忽略null,原本的类字段的值是null,映射出来是"",int? null + config.Default.NameMatchingStrategy(NameMatchingStrategy.IgnoreCase);//忽略大小写 + var destination = source.Adapt(config); + return destination; + } + } +} diff --git a/src/Khd.Core.Library/Swagger/AdditionOperationFilter.cs b/src/Khd.Core.Library/Swagger/AdditionOperationFilter.cs new file mode 100644 index 0000000..7308a46 --- /dev/null +++ b/src/Khd.Core.Library/Swagger/AdditionOperationFilter.cs @@ -0,0 +1,45 @@ +using Khd.Core.Library.Dto; +using Microsoft.OpenApi.Models; +using Swashbuckle.AspNetCore.SwaggerGen; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; + +namespace Khd.Core.Library.Swagger +{ + public class AdditionOperationFilter : IOperationFilter + { + public void Apply(OpenApiOperation operation, OperationFilterContext context) + { + if (context == null) return; + + var actualReturnType = context.MethodInfo.ReturnType.Name == "Task`1" + ? context.MethodInfo.ReturnType.GenericTypeArguments.FirstOrDefault() + : context.MethodInfo.ReturnType; + + if (actualReturnType == null || actualReturnType.Name == "ApiResult`1" || + actualReturnType.Name == "ApiResult") return; + + var wrapApiResultReturnType = actualReturnType == typeof(void) || actualReturnType == typeof(Task) + ? typeof(ApiResult) + : typeof(ApiResult<>).MakeGenericType(actualReturnType); + + operation?.Responses?.Remove("200"); + operation?.Responses?.Add("200", + new OpenApiResponse + { + Description = "Success", + Content = new Dictionary + { + { + "application/json", new OpenApiMediaType + { + Schema = context.SchemaGenerator.GenerateSchema(wrapApiResultReturnType, + context.SchemaRepository) + } + } + } + }); + } + } +} \ No newline at end of file diff --git a/src/Khd.Core.Library/Swagger/ApplicationBuilderSwaggerExtensions.cs b/src/Khd.Core.Library/Swagger/ApplicationBuilderSwaggerExtensions.cs new file mode 100644 index 0000000..944f18a --- /dev/null +++ b/src/Khd.Core.Library/Swagger/ApplicationBuilderSwaggerExtensions.cs @@ -0,0 +1,14 @@ +using Microsoft.AspNetCore.Builder; + +namespace Khd.Core.Library.Swagger +{ + public static class ApplicationBuilderSwaggerExtensions + { + public static IApplicationBuilder UseLibrarySwagger(this IApplicationBuilder app) + { + app.UseSwagger(); + app.UseSwaggerUI(); + return app; + } + } +} \ No newline at end of file diff --git a/src/Khd.Core.Library/Swagger/SecurityRequirementsOperationFilter.cs b/src/Khd.Core.Library/Swagger/SecurityRequirementsOperationFilter.cs new file mode 100644 index 0000000..741ae7e --- /dev/null +++ b/src/Khd.Core.Library/Swagger/SecurityRequirementsOperationFilter.cs @@ -0,0 +1,36 @@ +using Microsoft.AspNetCore.Authorization; +using Microsoft.OpenApi.Models; +using Swashbuckle.AspNetCore.SwaggerGen; +using System.Collections.Generic; +using System.Linq; + +namespace Khd.Core.Library.Swagger +{ + public class SecurityRequirementsOperationFilter : IOperationFilter + { + public void Apply(OpenApiOperation operation, OperationFilterContext context) + { + var actionAttrs = context.MethodInfo.GetCustomAttributes(true); + var controllerAttrs = context.MethodInfo.DeclaringType.GetCustomAttributes(true); + + if (actionAttrs.OfType().Any() || + controllerAttrs.OfType().Any()) return; + + var methodAuthorizeAttrs = actionAttrs.OfType(); + var controllerAuthorizeAttrs = controllerAttrs.OfType(); + + if (!methodAuthorizeAttrs.Any() && !controllerAuthorizeAttrs.Any()) return; + + operation.Responses.Add("401", new OpenApiResponse { Description = "Unauthorized" }); + + operation.Security.Add(new OpenApiSecurityRequirement + { + { + new OpenApiSecurityScheme + {Reference = new OpenApiReference {Type = ReferenceType.SecurityScheme, Id = "Bearer"}}, + new List() + } + }); + } + } +} \ No newline at end of file diff --git a/src/Khd.Core.Library/Swagger/ServiceCollectionSwaggerExtensions.cs b/src/Khd.Core.Library/Swagger/ServiceCollectionSwaggerExtensions.cs new file mode 100644 index 0000000..c619781 --- /dev/null +++ b/src/Khd.Core.Library/Swagger/ServiceCollectionSwaggerExtensions.cs @@ -0,0 +1,76 @@ +using Microsoft.AspNetCore.Builder; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.OpenApi.Models; +using Swashbuckle.AspNetCore.Swagger; +using Swashbuckle.AspNetCore.SwaggerGen; +using Swashbuckle.AspNetCore.SwaggerUI; +using System; +using System.IO; +using System.Reflection; + +namespace Khd.Core.Library.Swagger +{ + public static class ServiceCollectionSwaggerExtensions + { + public static IServiceCollection AddLibrarySwagger(this IServiceCollection services) + { + // 配置SwaggerGen + services.Configure(options => + { + options.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme + { + Description = "JWT模式授权,请输入 Bearer [Token] 进行身份验证", + Name = "Authorization", + In = ParameterLocation.Header, + Type = SecuritySchemeType.ApiKey + }); + + options.OperationFilter(); + options.OperationFilter(); + + var assemblyName = Assembly.GetEntryAssembly()?.GetName().Name; + if (assemblyName == null) + return; + + options.SwaggerDoc(assemblyName, new OpenApiInfo + { + Version = "v1", + Title = assemblyName, + Contact = new OpenApiContact() + { + Email = "kehaida@163.com", + Name = "khd", + Url = new Uri("https://github.com") + } + }); + options.CustomSchemaIds(t => t.FullName); + + // foreach (var xmlFile in Directory.EnumerateFiles(Directory.GetCurrentDirectory(), "Khd.*.xml")) + foreach (var xmlFile in Directory.EnumerateFiles(AppContext.BaseDirectory, "Khd.*.xml")) + options.IncludeXmlComments(xmlFile, true); + }); + + // 配置 SwaggerOptions + services.Configure(options => + { + options.RouteTemplate = "swagger/{documentName}/{Version}"; + }); + + // 配置 SwaggerUIOptions + services.Configure(options => + { + options.EnableDeepLinking(); + options.DocExpansion(DocExpansion.None); + options.DisplayRequestDuration(); + + var assemblyName = Assembly.GetEntryAssembly()?.GetName().Name; + + if (assemblyName != null) options.SwaggerEndpoint($"{assemblyName}/v1", "V1"); + }); + + services.AddSwaggerGen(); + + return services; + } + } +} \ No newline at end of file diff --git a/src/Khd.Core.Plc/Khd.Core.Plc.csproj b/src/Khd.Core.Plc/Khd.Core.Plc.csproj new file mode 100644 index 0000000..33ed615 --- /dev/null +++ b/src/Khd.Core.Plc/Khd.Core.Plc.csproj @@ -0,0 +1,13 @@ + + + + net6.0 + enable + enable + + + + + + + diff --git a/src/Khd.Core.Plc/S7/COTP.cs b/src/Khd.Core.Plc/S7/COTP.cs new file mode 100644 index 0000000..64f17f4 --- /dev/null +++ b/src/Khd.Core.Plc/S7/COTP.cs @@ -0,0 +1,113 @@ +namespace Khd.Core.Plc.S7 +{ + + /// + /// COTP Protocol functions and types + /// + internal class COTP + { + public enum PduType : byte + { + Data = 0xf0, + ConnectionConfirmed = 0xd0 + } + /// + /// Describes a COTP TPDU (Transport protocol data unit) + /// + public class TPDU + { + public TPKT TPkt { get; } + public byte HeaderLength; + public PduType PDUType; + public int TPDUNumber; + public byte[] Data; + public bool LastDataUnit; + + public TPDU(TPKT tPKT) + { + TPkt = tPKT; + + HeaderLength = tPKT.Data[0]; // Header length excluding this length byte + if (HeaderLength >= 2) + { + PDUType = (PduType)tPKT.Data[1]; + if (PDUType == PduType.Data) //DT Data + { + var flags = tPKT.Data[2]; + TPDUNumber = flags & 0x7F; + LastDataUnit = (flags & 0x80) > 0; + Data = new byte[tPKT.Data.Length - HeaderLength - 1]; // substract header length byte + header length. + Array.Copy(tPKT.Data, HeaderLength + 1, Data, 0, Data.Length); + return; + } + //TODO: Handle other PDUTypes + } + Data = new byte[0]; + } + + /// + /// Reads COTP TPDU (Transport protocol data unit) from the network stream + /// See: https://tools.ietf.org/html/rfc905 + /// + /// The socket to read from + /// COTP DPDU instance + public static async Task ReadAsync(Stream stream, CancellationToken cancellationToken) + { + var tpkt = await TPKT.ReadAsync(stream, cancellationToken).ConfigureAwait(false); + if (tpkt.Length == 0) + { + throw new TPDUInvalidException("No protocol data received"); + } + return new TPDU(tpkt); + } + + public override string ToString() + { + return string.Format("Length: {0} PDUType: {1} TPDUNumber: {2} Last: {3} Segment Data: {4}", + HeaderLength, + PDUType, + TPDUNumber, + LastDataUnit, + BitConverter.ToString(Data) + ); + } + + } + + /// + /// Describes a COTP TSDU (Transport service data unit). One TSDU consist of 1 ore more TPDUs + /// + public class TSDU + { + /// + /// Reads the full COTP TSDU (Transport service data unit) + /// See: https://tools.ietf.org/html/rfc905 + /// + /// The stream to read from + /// Data in TSDU + public static async Task ReadAsync(Stream stream, CancellationToken cancellationToken) + { + var segment = await TPDU.ReadAsync(stream, cancellationToken).ConfigureAwait(false); + + if (segment.LastDataUnit) + { + return segment.Data; + } + + // More segments are expected, prepare a buffer to store all data + var buffer = new byte[segment.Data.Length]; + Array.Copy(segment.Data, buffer, segment.Data.Length); + + while (!segment.LastDataUnit) + { + segment = await TPDU.ReadAsync(stream, cancellationToken).ConfigureAwait(false); + var previousLength = buffer.Length; + Array.Resize(ref buffer, buffer.Length + segment.Data.Length); + Array.Copy(segment.Data, 0, buffer, previousLength, segment.Data.Length); + } + + return buffer; + } + } + } +} diff --git a/src/Khd.Core.Plc/S7/Conversion.cs b/src/Khd.Core.Plc/S7/Conversion.cs new file mode 100644 index 0000000..f8a7ffb --- /dev/null +++ b/src/Khd.Core.Plc/S7/Conversion.cs @@ -0,0 +1,225 @@ +using System.Globalization; + +namespace Khd.Core.Plc.S7 +{ + /// + /// Conversion methods to convert from Siemens numeric format to C# and back + /// + public static class Conversion + { + /// + /// Converts a binary string to Int32 value + /// + /// + /// + public static int BinStringToInt32(this string txt) + { + int ret = 0; + + for (int i = 0; i < txt.Length; i++) + { + ret = (ret << 1) | ((txt[i] == '1') ? 1 : 0); + } + return ret; + } + + /// + /// Converts a binary string to a byte. Can return null. + /// + /// + /// + public static byte? BinStringToByte(this string txt) + { + if (txt.Length == 8) return (byte)BinStringToInt32(txt); + return null; + } + + /// + /// Converts the value to a binary string + /// + /// + /// + public static string ValToBinString(this object value) + { + int cnt = 0; + int cnt2 = 0; + int x = 0; + string txt = ""; + long longValue = 0; + + try + { + if (value.GetType().Name.IndexOf("[]") < 0) + { + // ist nur ein Wert + switch (value.GetType().Name) + { + case "Byte": + x = 7; + longValue = (long)((byte)value); + break; + case "Int16": + x = 15; + longValue = (long)((Int16)value); + break; + case "Int32": + x = 31; + longValue = (long)((Int32)value); + break; + case "Int64": + x = 63; + longValue = (long)((Int64)value); + break; + default: + throw new Exception(); + } + + for (cnt = x; cnt >= 0; cnt += -1) + { + if (((Int64)longValue & (Int64)Math.Pow(2, cnt)) > 0) + txt += "1"; + else + txt += "0"; + } + } + else + { + // ist ein Array + switch (value.GetType().Name) + { + case "Byte[]": + x = 7; + byte[] ByteArr = (byte[])value; + for (cnt2 = 0; cnt2 <= ByteArr.Length - 1; cnt2++) + { + for (cnt = x; cnt >= 0; cnt += -1) + if ((ByteArr[cnt2] & (byte)Math.Pow(2, cnt)) > 0) txt += "1"; else txt += "0"; + } + break; + case "Int16[]": + x = 15; + Int16[] Int16Arr = (Int16[])value; + for (cnt2 = 0; cnt2 <= Int16Arr.Length - 1; cnt2++) + { + for (cnt = x; cnt >= 0; cnt += -1) + if ((Int16Arr[cnt2] & (byte)Math.Pow(2, cnt)) > 0) txt += "1"; else txt += "0"; + } + break; + case "Int32[]": + x = 31; + Int32[] Int32Arr = (Int32[])value; + for (cnt2 = 0; cnt2 <= Int32Arr.Length - 1; cnt2++) + { + for (cnt = x; cnt >= 0; cnt += -1) + if ((Int32Arr[cnt2] & (byte)Math.Pow(2, cnt)) > 0) txt += "1"; else txt += "0"; + } + break; + case "Int64[]": + x = 63; + byte[] Int64Arr = (byte[])value; + for (cnt2 = 0; cnt2 <= Int64Arr.Length - 1; cnt2++) + { + for (cnt = x; cnt >= 0; cnt += -1) + if ((Int64Arr[cnt2] & (byte)Math.Pow(2, cnt)) > 0) txt += "1"; else txt += "0"; + } + break; + default: + throw new Exception(); + } + } + return txt; + } + catch + { + return ""; + } + } + + /// + /// Helper to get a bit value given a byte and the bit index. + /// Example: DB1.DBX0.5 -> var bytes = ReadBytes(DB1.DBW0); bool bit = bytes[0].SelectBit(5); + /// + /// + /// + /// + public static bool SelectBit(this byte data, int bitPosition) + { + int mask = 1 << bitPosition; + int result = data & mask; + + return (result != 0); + } + + /// + /// Converts from ushort value to short value; it's used to retrieve negative values from words + /// + /// + /// + public static short ConvertToShort(this ushort input) + { + short output; + output = short.Parse(input.ToString("X"), NumberStyles.HexNumber); + return output; + } + + /// + /// Converts from short value to ushort value; it's used to pass negative values to DWs + /// + /// + /// + public static ushort ConvertToUshort(this short input) + { + ushort output; + output = ushort.Parse(input.ToString("X"), NumberStyles.HexNumber); + return output; + } + + /// + /// Converts from UInt32 value to Int32 value; it's used to retrieve negative values from DBDs + /// + /// + /// + public static Int32 ConvertToInt(this uint input) + { + int output; + output = int.Parse(input.ToString("X"), NumberStyles.HexNumber); + return output; + } + + /// + /// Converts from Int32 value to UInt32 value; it's used to pass negative values to DBDs + /// + /// + /// + public static UInt32 ConvertToUInt(this int input) + { + uint output; + output = uint.Parse(input.ToString("X"), NumberStyles.HexNumber); + return output; + } + + /// + /// Converts from float to DWord (DBD) + /// + /// + /// + public static UInt32 ConvertToUInt(this float input) + { + uint output; + output = Khd.Core.Plc.S7.Types.DWord.FromByteArray(Khd.Core.Plc.S7.Types.Real.ToByteArray(input)); + return output; + } + + /// + /// Converts from DWord (DBD) to float + /// + /// + /// + public static float ConvertToFloat(this uint input) + { + float output; + output = Khd.Core.Plc.S7.Types.Real.FromByteArray(Khd.Core.Plc.S7.Types.DWord.ToByteArray(input)); + return output; + } + } +} diff --git a/src/Khd.Core.Plc/S7/Enums.cs b/src/Khd.Core.Plc/S7/Enums.cs new file mode 100644 index 0000000..01663ab --- /dev/null +++ b/src/Khd.Core.Plc/S7/Enums.cs @@ -0,0 +1,211 @@ +namespace Khd.Core.Plc.S7 +{ + /// + /// Types of S7 cpu supported by the library + /// + public enum CpuType + { + /// + /// S7 200 cpu type + /// + S7200 = 0, + + /// + /// Siemens Logo 0BA8 + /// + Logo0BA8 = 1, + + /// + /// S7 200 Smart + /// + S7200Smart = 2, + + /// + /// S7 300 cpu type + /// + S7300 = 10, + + /// + /// S7 400 cpu type + /// + S7400 = 20, + + /// + /// S7 1200 cpu type + /// + S71200 = 30, + + /// + /// S7 1500 cpu type + /// + S71500 = 40, + } + + /// + /// Types of error code that can be set after a function is called + /// + public enum ErrorCode + { + /// + /// The function has been executed correctly + /// + NoError = 0, + + /// + /// Wrong type of CPU error + /// + WrongCPU_Type = 1, + + /// + /// Connection error + /// + ConnectionError = 2, + + /// + /// Ip address not available + /// + IPAddressNotAvailable, + + /// + /// Wrong format of the variable + /// + WrongVarFormat = 10, + + /// + /// Wrong number of received bytes + /// + WrongNumberReceivedBytes = 11, + + /// + /// Error on send data + /// + SendData = 20, + + /// + /// Error on read data + /// + ReadData = 30, + + /// + /// Error on write data + /// + WriteData = 50 + } + + /// + /// Types of memory area that can be read + /// + public enum DataType + { + /// + /// Input area memory + /// + Input = 129, + + /// + /// Output area memory + /// + Output = 130, + + /// + /// Merkers area memory (M0, M0.0, ...) + /// + Memory = 131, + + /// + /// DB area memory (DB1, DB2, ...) + /// + DataBlock = 132, + + /// + /// Timer area memory(T1, T2, ...) + /// + Timer = 29, + + /// + /// Counter area memory (C1, C2, ...) + /// + Counter = 28 + } + + /// + /// Types + /// + public enum VarType + { + /// + /// S7 Bit variable type (bool) + /// + Bit, + + /// + /// S7 Byte variable type (8 bits) + /// + Byte, + + /// + /// S7 Word variable type (16 bits, 2 bytes) + /// + Word, + + /// + /// S7 DWord variable type (32 bits, 4 bytes) + /// + DWord, + + /// + /// S7 Int variable type (16 bits, 2 bytes) + /// + Int, + + /// + /// DInt variable type (32 bits, 4 bytes) + /// + DInt, + + /// + /// Real variable type (32 bits, 4 bytes) + /// + Real, + + /// + /// LReal variable type (64 bits, 8 bytes) + /// + LReal, + + /// + /// Char Array / C-String variable type (variable) + /// + String, + + /// + /// S7 String variable type (variable) + /// + S7String, + + /// + /// S7 WString variable type (variable) + /// + S7WString, + + /// + /// Timer variable type + /// + Timer, + + /// + /// Counter variable type + /// + Counter, + + /// + /// DateTIme variable type + /// + DateTime, + + /// + /// DateTimeLong variable type + /// + DateTimeLong + } +} diff --git a/src/Khd.Core.Plc/S7/Help/MemoryStreamExtension.cs b/src/Khd.Core.Plc/S7/Help/MemoryStreamExtension.cs new file mode 100644 index 0000000..60eceeb --- /dev/null +++ b/src/Khd.Core.Plc/S7/Help/MemoryStreamExtension.cs @@ -0,0 +1,18 @@ + +namespace Khd.Core.Plc.S7.Helper +{ + internal static class MemoryStreamExtension + { + /// + /// Helper function to write to whole content of the given byte array to a memory stream. + /// + /// Writes all bytes in value from 0 to value.Length to the memory stream. + /// + /// + /// + public static void WriteByteArray(this System.IO.MemoryStream stream, byte[] value) + { + stream.Write(value, 0, value.Length); + } + } +} diff --git a/src/Khd.Core.Plc/S7/Internal/TaskQueue.cs b/src/Khd.Core.Plc/S7/Internal/TaskQueue.cs new file mode 100644 index 0000000..2394fdf --- /dev/null +++ b/src/Khd.Core.Plc/S7/Internal/TaskQueue.cs @@ -0,0 +1,24 @@ +namespace Khd.Core.Plc.S7.Internal +{ + internal class TaskQueue + { + private static readonly object Sentinel = new object(); + + private Task prev = Task.FromResult(Sentinel); + + public async Task Enqueue(Func> action) + { + var tcs = new TaskCompletionSource(); + await Interlocked.Exchange(ref prev, tcs.Task).ConfigureAwait(false); + + try + { + return await action.Invoke().ConfigureAwait(false); + } + finally + { + tcs.SetResult(Sentinel); + } + } + } +} \ No newline at end of file diff --git a/src/Khd.Core.Plc/S7/InvalidDataException.cs b/src/Khd.Core.Plc/S7/InvalidDataException.cs new file mode 100644 index 0000000..5d03e7e --- /dev/null +++ b/src/Khd.Core.Plc/S7/InvalidDataException.cs @@ -0,0 +1,41 @@ +namespace Khd.Core.Plc.S7 +{ +#if NET_FULL + [Serializable] +#endif + public class InvalidDataException : Exception + { + public byte[] ReceivedData { get; } + public int ErrorIndex { get; } + public byte ExpectedValue { get; } + + public InvalidDataException(string message, byte[] receivedData, int errorIndex, byte expectedValue) + : base(FormatMessage(message, receivedData, errorIndex, expectedValue)) + { + ReceivedData = receivedData; + ErrorIndex = errorIndex; + ExpectedValue = expectedValue; + } + +#if NET_FULL + protected InvalidDataException(System.Runtime.Serialization.SerializationInfo info, + System.Runtime.Serialization.StreamingContext context) : base(info, context) + { + ReceivedData = (byte[]) info.GetValue(nameof(ReceivedData), typeof(byte[])); + ErrorIndex = info.GetInt32(nameof(ErrorIndex)); + ExpectedValue = info.GetByte(nameof(ExpectedValue)); + } +#endif + + private static string FormatMessage(string message, byte[] receivedData, int errorIndex, byte expectedValue) + { + if (errorIndex >= receivedData.Length) + throw new ArgumentOutOfRangeException(nameof(errorIndex), + $"{nameof(errorIndex)} {errorIndex} is outside the bounds of {nameof(receivedData)} with length {receivedData.Length}."); + + return $"{message} Invalid data received. Expected '{expectedValue}' at index {errorIndex}, " + + $"but received {receivedData[errorIndex]}. See the {nameof(ReceivedData)} property " + + "for the full message received."; + } + } +} \ No newline at end of file diff --git a/src/Khd.Core.Plc/S7/PLC.cs b/src/Khd.Core.Plc/S7/PLC.cs new file mode 100644 index 0000000..15c8909 --- /dev/null +++ b/src/Khd.Core.Plc/S7/PLC.cs @@ -0,0 +1,326 @@ +using Khd.Core.Plc.S7.Internal; +using Khd.Core.Plc.S7.Protocol; +using Khd.Core.Plc.S7.Types; +using System.Net.Sockets; + + +namespace Khd.Core.Plc.S7 +{ + /// + /// Creates an instance of S7.Net driver + /// + public partial class Plc : IDisposable + { + /// + /// The default port for the S7 protocol. + /// + public const int DefaultPort = 102; + + /// + /// The default timeout (in milliseconds) used for and . + /// + public const int DefaultTimeout = 10_000; + + private readonly TaskQueue queue = new TaskQueue(); + + //TCP connection to device + private TcpClient? tcpClient; + private NetworkStream? _stream; + + private int readTimeout = DefaultTimeout; // default no timeout + private int writeTimeout = DefaultTimeout; // default no timeout + + /// + /// IP address of the PLC + /// + public string IP { get; } + + /// + /// PORT Number of the PLC, default is 102 + /// + public int Port { get; } + + /// + /// The TSAP addresses used during the connection request. + /// + public TsapPair TsapPair { get; set; } + + /// + /// CPU type of the PLC + /// + public CpuType CPU { get; } + + /// + /// Rack of the PLC + /// + public Int16 Rack { get; } + + /// + /// Slot of the CPU of the PLC + /// + public Int16 Slot { get; } + + /// + /// Max PDU size this cpu supports + /// + public int MaxPDUSize { get; private set; } + + /// Gets or sets the amount of time that a read operation blocks waiting for data from PLC. + /// A that specifies the amount of time, in milliseconds, that will elapse before a read operation fails. The default value, , specifies that the read operation does not time out. + public int ReadTimeout + { + get => readTimeout; + set + { + readTimeout = value; + if (tcpClient != null) tcpClient.ReceiveTimeout = readTimeout; + } + } + + /// Gets or sets the amount of time that a write operation blocks waiting for data to PLC. + /// A that specifies the amount of time, in milliseconds, that will elapse before a write operation fails. The default value, , specifies that the write operation does not time out. + public int WriteTimeout + { + get => writeTimeout; + set + { + writeTimeout = value; + if (tcpClient != null) tcpClient.SendTimeout = writeTimeout; + } + } + + /// + /// Gets a value indicating whether a connection to the PLC has been established. + /// + /// + /// The property gets the connection state of the Client socket as + /// of the last I/O operation. When it returns false, the Client socket was either + /// never connected, or is no longer connected. + /// + /// + /// Because the property only reflects the state of the connection + /// as of the most recent operation, you should attempt to send or receive a message to + /// determine the current state. After the message send fails, this property no longer + /// returns true. Note that this behavior is by design. You cannot reliably test the + /// state of the connection because, in the time between the test and a send/receive, the + /// connection could have been lost. Your code should assume the socket is connected, and + /// gracefully handle failed transmissions. + /// + /// + public bool IsConnected => tcpClient?.Connected ?? false; + + /// + /// Creates a PLC object with all the parameters needed for connections. + /// For S7-1200 and S7-1500, the default is rack = 0 and slot = 0. + /// You need slot > 0 if you are connecting to external ethernet card (CP). + /// For S7-300 and S7-400 the default is rack = 0 and slot = 2. + /// + /// CpuType of the PLC (select from the enum) + /// Ip address of the PLC + /// rack of the PLC, usually it's 0, but check in the hardware configuration of Step7 or TIA portal + /// slot of the CPU of the PLC, usually it's 2 for S7300-S7400, 0 for S7-1200 and S7-1500. + /// If you use an external ethernet card, this must be set accordingly. + public Plc(CpuType cpu, string ip, Int16 rack, Int16 slot) + : this(cpu, ip, DefaultPort, rack, slot) + { + } + + /// + /// Creates a PLC object with all the parameters needed for connections. + /// For S7-1200 and S7-1500, the default is rack = 0 and slot = 0. + /// You need slot > 0 if you are connecting to external ethernet card (CP). + /// For S7-300 and S7-400 the default is rack = 0 and slot = 2. + /// + /// CpuType of the PLC (select from the enum) + /// Ip address of the PLC + /// Port number used for the connection, default 102. + /// rack of the PLC, usually it's 0, but check in the hardware configuration of Step7 or TIA portal + /// slot of the CPU of the PLC, usually it's 2 for S7300-S7400, 0 for S7-1200 and S7-1500. + /// If you use an external ethernet card, this must be set accordingly. + public Plc(CpuType cpu, string ip, int port, Int16 rack, Int16 slot) + : this(ip, port, TsapPair.GetDefaultTsapPair(cpu, rack, slot)) + { + if (!Enum.IsDefined(typeof(CpuType), cpu)) + throw new ArgumentException( + $"The value of argument '{nameof(cpu)}' ({cpu}) is invalid for Enum type '{typeof(CpuType).Name}'.", + nameof(cpu)); + + CPU = cpu; + Rack = rack; + Slot = slot; + } + + /// + /// Creates a PLC object with all the parameters needed for connections. + /// For S7-1200 and S7-1500, the default is rack = 0 and slot = 0. + /// You need slot > 0 if you are connecting to external ethernet card (CP). + /// For S7-300 and S7-400 the default is rack = 0 and slot = 2. + /// + /// Ip address of the PLC + /// The TSAP addresses used for the connection request. + public Plc(string ip, TsapPair tsapPair) : this(ip, DefaultPort, tsapPair) + { + } + + /// + /// Creates a PLC object with all the parameters needed for connections. Use this constructor + /// if you want to manually override the TSAP addresses used during the connection request. + /// + /// Ip address of the PLC + /// Port number used for the connection, default 102. + /// The TSAP addresses used for the connection request. + public Plc(string ip, int port, TsapPair tsapPair) + { + if (string.IsNullOrEmpty(ip)) + throw new ArgumentException("IP address must valid.", nameof(ip)); + + IP = ip; + Port = port; + MaxPDUSize = 240; + TsapPair = tsapPair; + } + + /// + /// Close connection to PLC + /// + public void Close() + { + if (tcpClient != null) + { + if (tcpClient.Connected) tcpClient.Close(); + tcpClient = null; // Can not reuse TcpClient once connection gets closed. + } + } + + private void AssertPduSizeForRead(ICollection dataItems) + { + // send request limit: 19 bytes of header data, 12 bytes of parameter data for each dataItem + var requiredRequestSize = 19 + dataItems.Count * 12; + if (requiredRequestSize > MaxPDUSize) throw new Exception($"Too many vars requested for read. Request size ({requiredRequestSize}) is larger than protocol limit ({MaxPDUSize})."); + + // response limit: 14 bytes of header data, 4 bytes of result data for each dataItem and the actual data + var requiredResponseSize = GetDataLength(dataItems) + dataItems.Count * 4 + 14; + if (requiredResponseSize > MaxPDUSize) throw new Exception($"Too much data requested for read. Response size ({requiredResponseSize}) is larger than protocol limit ({MaxPDUSize})."); + } + + private void AssertPduSizeForWrite(ICollection dataItems) + { + // 12 bytes of header data, 18 bytes of parameter data for each dataItem + if (dataItems.Count * 18 + 12 > MaxPDUSize) throw new Exception("Too many vars supplied for write"); + + // 12 bytes of header data, 16 bytes of data for each dataItem and the actual data + if (GetDataLength(dataItems) + dataItems.Count * 16 + 12 > MaxPDUSize) + throw new Exception("Too much data supplied for write"); + } + + private void ConfigureConnection() + { + if (tcpClient == null) + { + return; + } + + tcpClient.ReceiveTimeout = ReadTimeout; + tcpClient.SendTimeout = WriteTimeout; + } + + private int GetDataLength(IEnumerable dataItems) + { + // Odd length variables are 0-padded + return dataItems.Select(di => VarTypeToByteLength(di.VarType, di.Count)) + .Sum(len => (len & 1) == 1 ? len + 1 : len); + } + + private static void AssertReadResponse(byte[] s7Data, int dataLength) + { + var expectedLength = dataLength + 18; + + PlcException NotEnoughBytes() => + new PlcException(ErrorCode.WrongNumberReceivedBytes, + $"Received {s7Data.Length} bytes: '{BitConverter.ToString(s7Data)}', expected {expectedLength} bytes.") + ; + + if (s7Data == null) + throw new PlcException(ErrorCode.WrongNumberReceivedBytes, "No s7Data received."); + + if (s7Data.Length < 15) throw NotEnoughBytes(); + + ValidateResponseCode((ReadWriteErrorCode)s7Data[14]); + + if (s7Data.Length < expectedLength) throw NotEnoughBytes(); + } + + internal static void ValidateResponseCode(ReadWriteErrorCode statusCode) + { + switch (statusCode) + { + case ReadWriteErrorCode.ObjectDoesNotExist: + throw new Exception("Received error from PLC: Object does not exist."); + case ReadWriteErrorCode.DataTypeInconsistent: + throw new Exception("Received error from PLC: Data type inconsistent."); + case ReadWriteErrorCode.DataTypeNotSupported: + throw new Exception("Received error from PLC: Data type not supported."); + case ReadWriteErrorCode.AccessingObjectNotAllowed: + throw new Exception("Received error from PLC: Accessing object not allowed."); + case ReadWriteErrorCode.AddressOutOfRange: + throw new Exception("Received error from PLC: Address out of range."); + case ReadWriteErrorCode.HardwareFault: + throw new Exception("Received error from PLC: Hardware fault."); + case ReadWriteErrorCode.Success: + break; + default: + throw new Exception($"Invalid response from PLC: statusCode={(byte)statusCode}."); + } + } + + private Stream GetStreamIfAvailable() + { + if (_stream == null) + { + throw new PlcException(ErrorCode.ConnectionError, "Plc is not connected"); + } + + return _stream; + } + + #region IDisposable Support + private bool disposedValue = false; // To detect redundant calls + + /// + /// Dispose Plc Object + /// + /// + protected virtual void Dispose(bool disposing) + { + if (!disposedValue) + { + if (disposing) + { + Close(); + } + + // TODO: free unmanaged resources (unmanaged objects) and override a finalizer below. + // TODO: set large fields to null. + + disposedValue = true; + } + } + + // TODO: override a finalizer only if Dispose(bool disposing) above has code to free unmanaged resources. + // ~Plc() { + // // Do not change this code. Put cleanup code in Dispose(bool disposing) above. + // Dispose(false); + // } + + // This code added to correctly implement the disposable pattern. + void IDisposable.Dispose() + { + // Do not change this code. Put cleanup code in Dispose(bool disposing) above. + Dispose(true); + // TODO: uncomment the following line if the finalizer is overridden above. + // GC.SuppressFinalize(this); + } + #endregion + + } +} diff --git a/src/Khd.Core.Plc/S7/PLCAddress.cs b/src/Khd.Core.Plc/S7/PLCAddress.cs new file mode 100644 index 0000000..7c2bad1 --- /dev/null +++ b/src/Khd.Core.Plc/S7/PLCAddress.cs @@ -0,0 +1,207 @@ +namespace Khd.Core.Plc.S7 +{ + internal class PLCAddress + { + private DataType dataType; + private int dbNumber; + private int startByte; + private int bitNumber; + private VarType varType; + + public DataType DataType + { + get => dataType; + set => dataType = value; + } + + public int DbNumber + { + get => dbNumber; + set => dbNumber = value; + } + + public int StartByte + { + get => startByte; + set => startByte = value; + } + + public int BitNumber + { + get => bitNumber; + set => bitNumber = value; + } + + public VarType VarType + { + get => varType; + set => varType = value; + } + + public PLCAddress(string address) + { + Parse(address, out dataType, out dbNumber, out varType, out startByte, out bitNumber); + } + + public static void Parse(string input, out DataType dataType, out int dbNumber, out VarType varType, out int address, out int bitNumber) + { + bitNumber = -1; + dbNumber = 0; + + switch (input.Substring(0, 2)) + { + case "DB": + string[] strings = input.Split(new char[] { '.' }); + if (strings.Length < 2) + throw new InvalidAddressException("To few periods for DB address"); + + dataType = DataType.DataBlock; + dbNumber = int.Parse(strings[0].Substring(2)); + address = int.Parse(strings[1].Substring(3)); + + string dbType = strings[1].Substring(0, 3); + switch (dbType) + { + case "DBB": + varType = VarType.Byte; + return; + case "DBW": + varType = VarType.Word; + return; + case "DBD": + varType = VarType.DWord; + return; + case "DBX": + bitNumber = int.Parse(strings[2]); + if (bitNumber > 7) + throw new InvalidAddressException("Bit can only be 0-7"); + varType = VarType.Bit; + return; + default: + throw new InvalidAddressException(); + } + case "IB": + case "EB": + // Input byte + dataType = DataType.Input; + dbNumber = 0; + address = int.Parse(input.Substring(2)); + varType = VarType.Byte; + return; + case "IW": + case "EW": + // Input word + dataType = DataType.Input; + dbNumber = 0; + address = int.Parse(input.Substring(2)); + varType = VarType.Word; + return; + case "ID": + case "ED": + // Input double-word + dataType = DataType.Input; + dbNumber = 0; + address = int.Parse(input.Substring(2)); + varType = VarType.DWord; + return; + case "QB": + case "AB": + case "OB": + // Output byte + dataType = DataType.Output; + dbNumber = 0; + address = int.Parse(input.Substring(2)); + varType = VarType.Byte; + return; + case "QW": + case "AW": + case "OW": + // Output word + dataType = DataType.Output; + dbNumber = 0; + address = int.Parse(input.Substring(2)); + varType = VarType.Word; + return; + case "QD": + case "AD": + case "OD": + // Output double-word + dataType = DataType.Output; + dbNumber = 0; + address = int.Parse(input.Substring(2)); + varType = VarType.DWord; + return; + case "MB": + // Memory byte + dataType = DataType.Memory; + dbNumber = 0; + address = int.Parse(input.Substring(2)); + varType = VarType.Byte; + return; + case "MW": + // Memory word + dataType = DataType.Memory; + dbNumber = 0; + address = int.Parse(input.Substring(2)); + varType = VarType.Word; + return; + case "MD": + // Memory double-word + dataType = DataType.Memory; + dbNumber = 0; + address = int.Parse(input.Substring(2)); + varType = VarType.DWord; + return; + default: + switch (input.Substring(0, 1)) + { + case "E": + case "I": + // Input + dataType = DataType.Input; + varType = VarType.Bit; + break; + case "Q": + case "A": + case "O": + // Output + dataType = DataType.Output; + varType = VarType.Bit; + break; + case "M": + // Memory + dataType = DataType.Memory; + varType = VarType.Bit; + break; + case "T": + // Timer + dataType = DataType.Timer; + dbNumber = 0; + address = int.Parse(input.Substring(1)); + varType = VarType.Timer; + return; + case "Z": + case "C": + // Counter + dataType = DataType.Counter; + dbNumber = 0; + address = int.Parse(input.Substring(1)); + varType = VarType.Counter; + return; + default: + throw new InvalidAddressException(string.Format("{0} is not a valid address", input.Substring(0, 1))); + } + + string txt2 = input.Substring(1); + if (txt2.IndexOf(".") == -1) + throw new InvalidAddressException("To few periods for DB address"); + + address = int.Parse(txt2.Substring(0, txt2.IndexOf("."))); + bitNumber = int.Parse(txt2.Substring(txt2.IndexOf(".") + 1)); + if (bitNumber > 7) + throw new InvalidAddressException("Bit can only be 0-7"); + return; + } + } + } +} diff --git a/src/Khd.Core.Plc/S7/PLCExceptions.cs b/src/Khd.Core.Plc/S7/PLCExceptions.cs new file mode 100644 index 0000000..eb21fa8 --- /dev/null +++ b/src/Khd.Core.Plc/S7/PLCExceptions.cs @@ -0,0 +1,112 @@ +#if NET_FULL +using System.Runtime.Serialization; +#endif + + +namespace Khd.Core.Plc.S7 +{ + internal class WrongNumberOfBytesException : Exception + { + public WrongNumberOfBytesException() : base() + { + } + + public WrongNumberOfBytesException(string message) : base(message) + { + } + + public WrongNumberOfBytesException(string message, Exception innerException) : base(message, innerException) + { + } + +#if NET_FULL + protected WrongNumberOfBytesException(SerializationInfo info, StreamingContext context) : base(info, context) + { + } +#endif + } + + internal class InvalidAddressException : Exception + { + public InvalidAddressException() : base() + { + } + + public InvalidAddressException(string message) : base(message) + { + } + + public InvalidAddressException(string message, Exception innerException) : base(message, innerException) + { + } + +#if NET_FULL + protected InvalidAddressException(SerializationInfo info, StreamingContext context) : base(info, context) + { + } +#endif + } + + internal class InvalidVariableTypeException : Exception + { + public InvalidVariableTypeException() : base() + { + } + + public InvalidVariableTypeException(string message) : base(message) + { + } + + public InvalidVariableTypeException(string message, Exception innerException) : base(message, innerException) + { + } + +#if NET_FULL + protected InvalidVariableTypeException(SerializationInfo info, StreamingContext context) : base(info, context) + { + } +#endif + } + + internal class TPKTInvalidException : Exception + { + public TPKTInvalidException() : base() + { + } + + public TPKTInvalidException(string message) : base(message) + { + } + + public TPKTInvalidException(string message, Exception innerException) : base(message, innerException) + { + } + +#if NET_FULL + protected TPKTInvalidException(SerializationInfo info, StreamingContext context) : base(info, context) + { + } +#endif + } + + internal class TPDUInvalidException : Exception + { + public TPDUInvalidException() : base() + { + } + + public TPDUInvalidException(string message) : base(message) + { + } + + public TPDUInvalidException(string message, Exception innerException) : base(message, innerException) + { + } + +#if NET_FULL + protected TPDUInvalidException(SerializationInfo info, StreamingContext context) : base(info, context) + { + } +#endif + } +} diff --git a/src/Khd.Core.Plc/S7/PLCHelpers.cs b/src/Khd.Core.Plc/S7/PLCHelpers.cs new file mode 100644 index 0000000..4592ffe --- /dev/null +++ b/src/Khd.Core.Plc/S7/PLCHelpers.cs @@ -0,0 +1,266 @@ +using Khd.Core.Plc.S7.Helper; +using Khd.Core.Plc.S7.Protocol.S7; +using Khd.Core.Plc.S7.Types; +using DateTime = Khd.Core.Plc.S7.Types.DateTime; +using Timer = Khd.Core.Plc.S7.Types.Timer; + +namespace Khd.Core.Plc.S7 +{ + public partial class Plc + { + /// + /// Creates the header to read bytes from the PLC + /// + /// + /// + private static void BuildHeaderPackage(System.IO.MemoryStream stream, int amount = 1) + { + //header size = 19 bytes + stream.WriteByteArray(new byte[] { 0x03, 0x00 }); + //complete package size + stream.WriteByteArray(Types.Int.ToByteArray((short)(19 + (12 * amount)))); + stream.WriteByteArray(new byte[] { 0x02, 0xf0, 0x80, 0x32, 0x01, 0x00, 0x00, 0x00, 0x00 }); + //data part size + stream.WriteByteArray(Types.Word.ToByteArray((ushort)(2 + (amount * 12)))); + stream.WriteByteArray(new byte[] { 0x00, 0x00, 0x04 }); + //amount of requests + stream.WriteByte((byte)amount); + } + + /// + /// Create the bytes-package to request data from the PLC. You have to specify the memory type (dataType), + /// the address of the memory, the address of the byte and the bytes count. + /// + /// MemoryType (DB, Timer, Counter, etc.) + /// Address of the memory to be read + /// Start address of the byte + /// Number of bytes to be read + /// + private static void BuildReadDataRequestPackage(System.IO.MemoryStream stream, DataType dataType, int db, int startByteAdr, int count = 1) + { + //single data req = 12 + stream.WriteByteArray(new byte[] { 0x12, 0x0a, 0x10 }); + switch (dataType) + { + case DataType.Timer: + case DataType.Counter: + stream.WriteByte((byte)dataType); + break; + default: + stream.WriteByte(0x02); + break; + } + + stream.WriteByteArray(Word.ToByteArray((ushort)(count))); + stream.WriteByteArray(Word.ToByteArray((ushort)(db))); + stream.WriteByte((byte)dataType); + var overflow = (int)(startByteAdr * 8 / 0xffffU); // handles words with address bigger than 8191 + stream.WriteByte((byte)overflow); + switch (dataType) + { + case DataType.Timer: + case DataType.Counter: + stream.WriteByteArray(Types.Word.ToByteArray((ushort)(startByteAdr))); + break; + default: + stream.WriteByteArray(Types.Word.ToByteArray((ushort)((startByteAdr) * 8))); + break; + } + } + + /// + /// Given a S7 variable type (Bool, Word, DWord, etc.), it converts the bytes in the appropriate C# format. + /// + /// + /// + /// + /// + /// + private object? ParseBytes(VarType varType, byte[] bytes, int varCount, byte bitAdr = 0) + { + if (bytes == null || bytes.Length == 0) + return null; + + switch (varType) + { + case VarType.Byte: + if (varCount == 1) + return bytes[0]; + else + return bytes; + case VarType.Word: + if (varCount == 1) + return Word.FromByteArray(bytes); + else + return Word.ToArray(bytes); + case VarType.Int: + if (varCount == 1) + return Int.FromByteArray(bytes); + else + return Int.ToArray(bytes); + case VarType.DWord: + if (varCount == 1) + return DWord.FromByteArray(bytes); + else + return DWord.ToArray(bytes); + case VarType.DInt: + if (varCount == 1) + return DInt.FromByteArray(bytes); + else + return DInt.ToArray(bytes); + case VarType.Real: + if (varCount == 1) + return Types.Real.FromByteArray(bytes); + else + return Types.Real.ToArray(bytes); + case VarType.LReal: + if (varCount == 1) + return Types.LReal.FromByteArray(bytes); + else + return Types.LReal.ToArray(bytes); + + case VarType.String: + return Types.String.FromByteArray(bytes); + case VarType.S7String: + return S7String.FromByteArray(bytes); + case VarType.S7WString: + return S7WString.FromByteArray(bytes); + + case VarType.Timer: + if (varCount == 1) + return Timer.FromByteArray(bytes); + else + return Timer.ToArray(bytes); + case VarType.Counter: + if (varCount == 1) + return Counter.FromByteArray(bytes); + else + return Counter.ToArray(bytes); + case VarType.Bit: + if (varCount == 1) + { + if (bitAdr > 7) + return null; + else + return Bit.FromByte(bytes[0], bitAdr); + } + else + { + return Bit.ToBitArray(bytes, varCount); + } + case VarType.DateTime: + if (varCount == 1) + { + return DateTime.FromByteArray(bytes); + } + else + { + return DateTime.ToArray(bytes); + } + case VarType.DateTimeLong: + if (varCount == 1) + { + return DateTimeLong.FromByteArray(bytes); + } + else + { + return DateTimeLong.ToArray(bytes); + } + default: + return null; + } + } + + /// + /// Given a S7 (Bool, Word, DWord, etc.), it returns how many bytes to read. + /// + /// + /// + /// Byte lenght of variable + internal static int VarTypeToByteLength(VarType varType, int varCount = 1) + { + switch (varType) + { + case VarType.Bit: + return (varCount + 7) / 8; + case VarType.Byte: + return (varCount < 1) ? 1 : varCount; + case VarType.String: + return varCount; + case VarType.S7String: + return ((varCount + 2) & 1) == 1 ? (varCount + 3) : (varCount + 2); + case VarType.S7WString: + return (varCount * 2) + 4; + case VarType.Word: + case VarType.Timer: + case VarType.Int: + case VarType.Counter: + return varCount * 2; + case VarType.DWord: + case VarType.DInt: + case VarType.Real: + return varCount * 4; + case VarType.LReal: + case VarType.DateTime: + return varCount * 8; + case VarType.DateTimeLong: + return varCount * 12; + default: + return 0; + } + } + + private byte[] GetS7ConnectionSetup() + { + return new byte[] { 3, 0, 0, 25, 2, 240, 128, 50, 1, 0, 0, 255, 255, 0, 8, 0, 0, 240, 0, 0, 3, 0, 3, + 3, 192 // Use 960 PDU size + }; + } + + private void ParseDataIntoDataItems(byte[] s7data, List dataItems) + { + int offset = 14; + foreach (var dataItem in dataItems) + { + // check for Return Code = Success + if (s7data[offset] != 0xff) + throw new PlcException(ErrorCode.WrongNumberReceivedBytes); + + // to Data bytes + offset += 4; + + int byteCnt = VarTypeToByteLength(dataItem.VarType, dataItem.Count); + dataItem.Value = ParseBytes( + dataItem.VarType, + s7data.Skip(offset).Take(byteCnt).ToArray(), + dataItem.Count, + dataItem.BitAdr + ); + + // next Item + offset += byteCnt; + + // Always align to even offset + if (offset % 2 != 0) + offset++; + } + } + + private static byte[] BuildReadRequestPackage(IList dataItems) + { + int packageSize = 19 + (dataItems.Count * 12); + var package = new System.IO.MemoryStream(packageSize); + + BuildHeaderPackage(package, dataItems.Count); + + foreach (var dataItem in dataItems) + { + BuildReadDataRequestPackage(package, dataItem.DataType, dataItem.DB, dataItem.StartByteAddress, dataItem.ByteLength); + } + + return package.ToArray(); + } + + + } +} diff --git a/src/Khd.Core.Plc/S7/PlcAsynchronous.cs b/src/Khd.Core.Plc/S7/PlcAsynchronous.cs new file mode 100644 index 0000000..53812df --- /dev/null +++ b/src/Khd.Core.Plc/S7/PlcAsynchronous.cs @@ -0,0 +1,560 @@ +using Khd.Core.Plc.S7.Protocol; +using Khd.Core.Plc.S7.Protocol.S7; +using Khd.Core.Plc.S7.Types; +using System.Net.Sockets; + +namespace Khd.Core.Plc.S7 +{ + /// + /// Creates an instance of S7.Net driver + /// + public partial class Plc + { + /// + /// Connects to the PLC and performs a COTP ConnectionRequest and S7 CommunicationSetup. + /// + /// The token to monitor for cancellation requests. The default value is None. + /// Please note that the cancellation will not affect opening the socket in any way and only affects data transfers for configuring the connection after the socket connection is successfully established. + /// Please note that cancellation is advisory/cooperative and will not lead to immediate cancellation in all cases. + /// A task that represents the asynchronous open operation. + public async Task OpenAsync(CancellationToken cancellationToken = default) + { + var stream = await ConnectAsync().ConfigureAwait(false); + try + { + await queue.Enqueue(async () => + { + cancellationToken.ThrowIfCancellationRequested(); + await EstablishConnection(stream, cancellationToken).ConfigureAwait(false); + _stream = stream; + + return default(object); + }).ConfigureAwait(false); + } + catch (Exception) + { + stream.Dispose(); + throw; + } + } + + private async Task ConnectAsync() + { + tcpClient = new TcpClient(); + ConfigureConnection(); + await tcpClient.ConnectAsync(IP, Port).ConfigureAwait(false); + return tcpClient.GetStream(); + } + + private async Task EstablishConnection(Stream stream, CancellationToken cancellationToken) + { + await RequestConnection(stream, cancellationToken).ConfigureAwait(false); + await SetupConnection(stream, cancellationToken).ConfigureAwait(false); + } + + private async Task RequestConnection(Stream stream, CancellationToken cancellationToken) + { + var requestData = ConnectionRequest.GetCOTPConnectionRequest(TsapPair); + var response = await NoLockRequestTpduAsync(stream, requestData, cancellationToken).ConfigureAwait(false); + + if (response.PDUType != COTP.PduType.ConnectionConfirmed) + { + throw new InvalidDataException("Connection request was denied", response.TPkt.Data, 1, 0x0d); + } + } + + private async Task SetupConnection(Stream stream, CancellationToken cancellationToken) + { + var setupData = GetS7ConnectionSetup(); + + var s7data = await NoLockRequestTsduAsync(stream, setupData, 0, setupData.Length, cancellationToken) + .ConfigureAwait(false); + + if (s7data.Length < 2) + throw new WrongNumberOfBytesException("Not enough data received in response to Communication Setup"); + + //Check for S7 Ack Data + if (s7data[1] != 0x03) + throw new InvalidDataException("Error reading Communication Setup response", s7data, 1, 0x03); + + if (s7data.Length < 20) + throw new WrongNumberOfBytesException("Not enough data received in response to Communication Setup"); + + // TODO: check if this should not rather be UInt16. + MaxPDUSize = s7data[18] * 256 + s7data[19]; + } + + + /// + /// Reads a number of bytes from a DB starting from a specified index. This handles more than 200 bytes with multiple requests. + /// If the read was not successful, check LastErrorCode or LastErrorString. + /// + /// Data type of the memory area, can be DB, Timer, Counter, Merker(Memory), Input, Output. + /// Address of the memory area (if you want to read DB1, this is set to 1). This must be set also for other memory area types: counters, timers,etc. + /// Start byte address. If you want to read DB1.DBW200, this is 200. + /// Byte count, if you want to read 120 bytes, set this to 120. + /// The token to monitor for cancellation requests. The default value is None. + /// Please note that cancellation is advisory/cooperative and will not lead to immediate cancellation in all cases. + /// Returns the bytes in an array + public async Task ReadBytesAsync(DataType dataType, int db, int startByteAdr, int count, CancellationToken cancellationToken = default) + { + var resultBytes = new byte[count]; + int index = 0; + while (count > 0) + { + //This works up to MaxPDUSize-1 on SNAP7. But not MaxPDUSize-0. + var maxToRead = Math.Min(count, MaxPDUSize - 18); + await ReadBytesWithSingleRequestAsync(dataType, db, startByteAdr + index, resultBytes, index, maxToRead, cancellationToken).ConfigureAwait(false); + count -= maxToRead; + index += maxToRead; + } + return resultBytes; + } + + /// + /// Read and decode a certain number of bytes of the "VarType" provided. + /// This can be used to read multiple consecutive variables of the same type (Word, DWord, Int, etc). + /// If the read was not successful, check LastErrorCode or LastErrorString. + /// + /// Data type of the memory area, can be DB, Timer, Counter, Merker(Memory), Input, Output. + /// Address of the memory area (if you want to read DB1, this is set to 1). This must be set also for other memory area types: counters, timers,etc. + /// Start byte address. If you want to read DB1.DBW200, this is 200. + /// Type of the variable/s that you are reading + /// Address of bit. If you want to read DB1.DBX200.6, set 6 to this parameter. + /// + /// The token to monitor for cancellation requests. The default value is None. + /// Please note that cancellation is advisory/cooperative and will not lead to immediate cancellation in all cases. + public async Task ReadAsync(DataType dataType, int db, int startByteAdr, VarType varType, int varCount, byte bitAdr = 0, CancellationToken cancellationToken = default) + { + int cntBytes = VarTypeToByteLength(varType, varCount); + byte[] bytes = await ReadBytesAsync(dataType, db, startByteAdr, cntBytes, cancellationToken).ConfigureAwait(false); + return ParseBytes(varType, bytes, varCount, bitAdr); + } + + /// + /// Reads a single variable from the PLC, takes in input strings like "DB1.DBX0.0", "DB20.DBD200", "MB20", "T45", etc. + /// If the read was not successful, check LastErrorCode or LastErrorString. + /// + /// Input strings like "DB1.DBX0.0", "DB20.DBD200", "MB20", "T45", etc. + /// The token to monitor for cancellation requests. The default value is None. + /// Please note that cancellation is advisory/cooperative and will not lead to immediate cancellation in all cases. + /// Returns an object that contains the value. This object must be cast accordingly. + public async Task ReadAsync(string variable, CancellationToken cancellationToken = default) + { + var adr = new PLCAddress(variable); + return await ReadAsync(adr.DataType, adr.DbNumber, adr.StartByte, adr.VarType, 1, (byte)adr.BitNumber, cancellationToken).ConfigureAwait(false); + } + + /// + /// Reads all the bytes needed to fill a struct in C#, starting from a certain address, and return an object that can be casted to the struct. + /// + /// Type of the struct to be readed (es.: TypeOf(MyStruct)). + /// Address of the DB. + /// Start byte address. If you want to read DB1.DBW200, this is 200. + /// The token to monitor for cancellation requests. The default value is None. + /// Please note that cancellation is advisory/cooperative and will not lead to immediate cancellation in all cases. + /// Returns a struct that must be cast. + public async Task ReadStructAsync(Type structType, int db, int startByteAdr = 0, CancellationToken cancellationToken = default) + { + int numBytes = Types.Struct.GetStructSize(structType); + // now read the package + var resultBytes = await ReadBytesAsync(DataType.DataBlock, db, startByteAdr, numBytes, cancellationToken).ConfigureAwait(false); + + // and decode it + return Types.Struct.FromBytes(structType, resultBytes); + } + + /// + /// Reads all the bytes needed to fill a struct in C#, starting from a certain address, and returns the struct or null if nothing was read. + /// + /// The struct type + /// Address of the DB. + /// Start byte address. If you want to read DB1.DBW200, this is 200. + /// The token to monitor for cancellation requests. The default value is None. + /// Please note that cancellation is advisory/cooperative and will not lead to immediate cancellation in all cases. + /// Returns a nulable struct. If nothing was read null will be returned. + public async Task ReadStructAsync(int db, int startByteAdr = 0, CancellationToken cancellationToken = default) where T : struct + { + return await ReadStructAsync(typeof(T), db, startByteAdr, cancellationToken).ConfigureAwait(false) as T?; + } + + /// + /// Reads all the bytes needed to fill a class in C#, starting from a certain address, and set all the properties values to the value that are read from the PLC. + /// This reads only properties, it doesn't read private variable or public variable without {get;set;} specified. + /// + /// Instance of the class that will store the values + /// Index of the DB; es.: 1 is for DB1 + /// Start byte address. If you want to read DB1.DBW200, this is 200. + /// The token to monitor for cancellation requests. The default value is None. + /// Please note that cancellation is advisory/cooperative and will not lead to immediate cancellation in all cases. + /// The number of read bytes + public async Task> ReadClassAsync(object sourceClass, int db, int startByteAdr = 0, CancellationToken cancellationToken = default) + { + int numBytes = (int)Class.GetClassSize(sourceClass); + if (numBytes <= 0) + { + throw new Exception("The size of the class is less than 1 byte and therefore cannot be read"); + } + + // now read the package + var resultBytes = await ReadBytesAsync(DataType.DataBlock, db, startByteAdr, numBytes, cancellationToken).ConfigureAwait(false); + // and decode it + Class.FromBytes(sourceClass, resultBytes); + + return new Tuple(resultBytes.Length, sourceClass); + } + + /// + /// Reads all the bytes needed to fill a class in C#, starting from a certain address, and set all the properties values to the value that are read from the PLC. + /// This reads only properties, it doesn't read private variable or public variable without {get;set;} specified. To instantiate the class defined by the generic + /// type, the class needs a default constructor. + /// + /// The class that will be instantiated. Requires a default constructor + /// Index of the DB; es.: 1 is for DB1 + /// Start byte address. If you want to read DB1.DBW200, this is 200. + /// The token to monitor for cancellation requests. The default value is None. + /// Please note that cancellation is advisory/cooperative and will not lead to immediate cancellation in all cases. + /// An instance of the class with the values read from the PLC. If no data has been read, null will be returned + public async Task ReadClassAsync(int db, int startByteAdr = 0, CancellationToken cancellationToken = default) where T : class + { + return await ReadClassAsync(() => Activator.CreateInstance(), db, startByteAdr, cancellationToken).ConfigureAwait(false); + } + + /// + /// Reads all the bytes needed to fill a class in C#, starting from a certain address, and set all the properties values to the value that are read from the PLC. + /// This reads only properties, it doesn't read private variable or public variable without {get;set;} specified. + /// + /// The class that will be instantiated + /// Function to instantiate the class + /// Index of the DB; es.: 1 is for DB1 + /// Start byte address. If you want to read DB1.DBW200, this is 200. + /// The token to monitor for cancellation requests. The default value is None. + /// Please note that cancellation is advisory/cooperative and will not lead to immediate cancellation in all cases. + /// An instance of the class with the values read from the PLC. If no data has been read, null will be returned + public async Task ReadClassAsync(Func classFactory, int db, int startByteAdr = 0, CancellationToken cancellationToken = default) where T : class + { + var instance = classFactory(); + var res = await ReadClassAsync(instance, db, startByteAdr, cancellationToken).ConfigureAwait(false); + int readBytes = res.Item1; + if (readBytes <= 0) + { + return null; + } + + return (T)res.Item2; + } + + /// + /// Reads multiple vars in a single request. + /// You have to create and pass a list of DataItems and you obtain in response the same list with the values. + /// Values are stored in the property "Value" of the dataItem and are already converted. + /// If you don't want the conversion, just create a dataItem of bytes. + /// The number of DataItems as well as the total size of the requested data can not exceed a certain limit (protocol restriction). + /// + /// List of dataitems that contains the list of variables that must be read. + /// The token to monitor for cancellation requests. The default value is None. + /// Please note that cancellation is advisory/cooperative and will not lead to immediate cancellation in all cases. + public async Task> ReadMultipleVarsAsync(List dataItems, CancellationToken cancellationToken = default) + { + //Snap7 seems to choke on PDU sizes above 256 even if snap7 + //replies with bigger PDU size in connection setup. + AssertPduSizeForRead(dataItems); + + try + { + var dataToSend = BuildReadRequestPackage(dataItems.Select(d => DataItem.GetDataItemAddress(d)).ToList()); + var s7data = await RequestTsduAsync(dataToSend, cancellationToken); + + ValidateResponseCode((ReadWriteErrorCode)s7data[14]); + + ParseDataIntoDataItems(s7data, dataItems); + } + catch (SocketException socketException) + { + throw new PlcException(ErrorCode.ReadData, socketException); + } + catch (OperationCanceledException) + { + throw; + } + catch (Exception exc) + { + throw new PlcException(ErrorCode.ReadData, exc); + } + return dataItems; + } + + + /// + /// Write a number of bytes from a DB starting from a specified index. This handles more than 200 bytes with multiple requests. + /// If the write was not successful, check LastErrorCode or LastErrorString. + /// + /// Data type of the memory area, can be DB, Timer, Counter, Merker(Memory), Input, Output. + /// Address of the memory area (if you want to read DB1, this is set to 1). This must be set also for other memory area types: counters, timers,etc. + /// Start byte address. If you want to write DB1.DBW200, this is 200. + /// Bytes to write. If more than 200, multiple requests will be made. + /// The token to monitor for cancellation requests. The default value is None. + /// Please note that cancellation is advisory/cooperative and will not lead to immediate cancellation in all cases. + /// A task that represents the asynchronous write operation. + public async Task WriteBytesAsync(DataType dataType, int db, int startByteAdr, byte[] value, CancellationToken cancellationToken = default) + { + int localIndex = 0; + int count = value.Length; + while (count > 0) + { + var maxToWrite = (int)Math.Min(count, MaxPDUSize - 35); + await WriteBytesWithASingleRequestAsync(dataType, db, startByteAdr + localIndex, value, localIndex, maxToWrite, cancellationToken).ConfigureAwait(false); + count -= maxToWrite; + localIndex += maxToWrite; + } + } + + /// + /// Write a single bit from a DB with the specified index. + /// + /// Data type of the memory area, can be DB, Timer, Counter, Merker(Memory), Input, Output. + /// Address of the memory area (if you want to read DB1, this is set to 1). This must be set also for other memory area types: counters, timers,etc. + /// Start byte address. If you want to write DB1.DBW200, this is 200. + /// The address of the bit. (0-7) + /// Bytes to write. If more than 200, multiple requests will be made. + /// The token to monitor for cancellation requests. The default value is None. + /// Please note that cancellation is advisory/cooperative and will not lead to immediate cancellation in all cases. + /// A task that represents the asynchronous write operation. + public async Task WriteBitAsync(DataType dataType, int db, int startByteAdr, int bitAdr, bool value, CancellationToken cancellationToken = default) + { + if (bitAdr < 0 || bitAdr > 7) + throw new InvalidAddressException(string.Format("Addressing Error: You can only reference bitwise locations 0-7. Address {0} is invalid", bitAdr)); + + await WriteBitWithASingleRequestAsync(dataType, db, startByteAdr, bitAdr, value, cancellationToken).ConfigureAwait(false); + } + + /// + /// Write a single bit from a DB with the specified index. + /// + /// Data type of the memory area, can be DB, Timer, Counter, Merker(Memory), Input, Output. + /// Address of the memory area (if you want to read DB1, this is set to 1). This must be set also for other memory area types: counters, timers,etc. + /// Start byte address. If you want to write DB1.DBW200, this is 200. + /// The address of the bit. (0-7) + /// Bytes to write. If more than 200, multiple requests will be made. + /// The token to monitor for cancellation requests. The default value is None. + /// Please note that cancellation is advisory/cooperative and will not lead to immediate cancellation in all cases. + /// A task that represents the asynchronous write operation. + public async Task WriteBitAsync(DataType dataType, int db, int startByteAdr, int bitAdr, int value, CancellationToken cancellationToken = default) + { + if (value < 0 || value > 1) + throw new ArgumentException("Value must be 0 or 1", nameof(value)); + + await WriteBitAsync(dataType, db, startByteAdr, bitAdr, value == 1, cancellationToken).ConfigureAwait(false); + } + + /// + /// Takes in input an object and tries to parse it to an array of values. This can be used to write many data, all of the same type. + /// You must specify the memory area type, memory are address, byte start address and bytes count. + /// If the read was not successful, check LastErrorCode or LastErrorString. + /// + /// Data type of the memory area, can be DB, Timer, Counter, Merker(Memory), Input, Output. + /// Address of the memory area (if you want to read DB1, this is set to 1). This must be set also for other memory area types: counters, timers,etc. + /// Start byte address. If you want to read DB1.DBW200, this is 200. + /// Bytes to write. The lenght of this parameter can't be higher than 200. If you need more, use recursion. + /// The address of the bit. (0-7) + /// The token to monitor for cancellation requests. The default value is None. + /// Please note that cancellation is advisory/cooperative and will not lead to immediate cancellation in all cases. + /// A task that represents the asynchronous write operation. + public async Task WriteAsync(DataType dataType, int db, int startByteAdr, object value, int bitAdr = -1, CancellationToken cancellationToken = default) + { + if (bitAdr != -1) + { + //Must be writing a bit value as bitAdr is specified + if (value is bool boolean) + { + await WriteBitAsync(dataType, db, startByteAdr, bitAdr, boolean, cancellationToken).ConfigureAwait(false); + } + else if (value is int intValue) + { + if (intValue < 0 || intValue > 7) + throw new ArgumentOutOfRangeException( + string.Format( + "Addressing Error: You can only reference bitwise locations 0-7. Address {0} is invalid", + bitAdr), nameof(bitAdr)); + + await WriteBitAsync(dataType, db, startByteAdr, bitAdr, intValue == 1, cancellationToken).ConfigureAwait(false); + } + else throw new ArgumentException("Value must be a bool or an int to write a bit", nameof(value)); + } + else await WriteBytesAsync(dataType, db, startByteAdr, Serialization.SerializeValue(value), cancellationToken).ConfigureAwait(false); + } + + /// + /// Writes a single variable from the PLC, takes in input strings like "DB1.DBX0.0", "DB20.DBD200", "MB20", "T45", etc. + /// If the write was not successful, check or . + /// + /// Input strings like "DB1.DBX0.0", "DB20.DBD200", "MB20", "T45", etc. + /// Value to be written to the PLC + /// The token to monitor for cancellation requests. The default value is None. + /// Please note that cancellation is advisory/cooperative and will not lead to immediate cancellation in all cases. + /// A task that represents the asynchronous write operation. + public async Task WriteAsync(string variable, object value, CancellationToken cancellationToken = default) + { + var adr = new PLCAddress(variable); + await WriteAsync(adr.DataType, adr.DbNumber, adr.StartByte, value, adr.BitNumber, cancellationToken).ConfigureAwait(false); + } + + /// + /// Writes a C# struct to a DB in the PLC + /// + /// The struct to be written + /// Db address + /// Start bytes on the PLC + /// The token to monitor for cancellation requests. The default value is None. + /// Please note that cancellation is advisory/cooperative and will not lead to immediate cancellation in all cases. + /// A task that represents the asynchronous write operation. + public async Task WriteStructAsync(object structValue, int db, int startByteAdr = 0, CancellationToken cancellationToken = default) + { + var bytes = Struct.ToBytes(structValue).ToList(); + await WriteBytesAsync(DataType.DataBlock, db, startByteAdr, bytes.ToArray(), cancellationToken).ConfigureAwait(false); + } + + /// + /// Writes a C# class to a DB in the PLC + /// + /// The class to be written + /// Db address + /// Start bytes on the PLC + /// The token to monitor for cancellation requests. The default value is None. + /// Please note that cancellation is advisory/cooperative and will not lead to immediate cancellation in all cases. + /// A task that represents the asynchronous write operation. + public async Task WriteClassAsync(object classValue, int db, int startByteAdr = 0, CancellationToken cancellationToken = default) + { + byte[] bytes = new byte[(int)Class.GetClassSize(classValue)]; + Types.Class.ToBytes(classValue, bytes); + await WriteBytesAsync(DataType.DataBlock, db, startByteAdr, bytes, cancellationToken).ConfigureAwait(false); + } + + private async Task ReadBytesWithSingleRequestAsync(DataType dataType, int db, int startByteAdr, byte[] buffer, int offset, int count, CancellationToken cancellationToken) + { + var dataToSend = BuildReadRequestPackage(new[] { new DataItemAddress(dataType, db, startByteAdr, count) }); + + var s7data = await RequestTsduAsync(dataToSend, cancellationToken); + AssertReadResponse(s7data, count); + + Array.Copy(s7data, 18, buffer, offset, count); + } + + /// + /// Write DataItem(s) to the PLC. Throws an exception if the response is invalid + /// or when the PLC reports errors for item(s) written. + /// + /// The DataItem(s) to write to the PLC. + /// Task that completes when response from PLC is parsed. + public async Task WriteAsync(params DataItem[] dataItems) + { + AssertPduSizeForWrite(dataItems); + + var message = new ByteArray(); + var length = S7WriteMultiple.CreateRequest(message, dataItems); + + var response = await RequestTsduAsync(message.Array, 0, length).ConfigureAwait(false); + + S7WriteMultiple.ParseResponse(response, response.Length, dataItems); + } + + /// + /// Writes up to 200 bytes to the PLC. You must specify the memory area type, memory are address, byte start address and bytes count. + /// + /// Data type of the memory area, can be DB, Timer, Counter, Merker(Memory), Input, Output. + /// Address of the memory area (if you want to read DB1, this is set to 1). This must be set also for other memory area types: counters, timers,etc. + /// Start byte address. If you want to read DB1.DBW200, this is 200. + /// Bytes to write. The lenght of this parameter can't be higher than 200. If you need more, use recursion. + /// A task that represents the asynchronous write operation. + private async Task WriteBytesWithASingleRequestAsync(DataType dataType, int db, int startByteAdr, byte[] value, int dataOffset, int count, CancellationToken cancellationToken) + { + try + { + var dataToSend = BuildWriteBytesPackage(dataType, db, startByteAdr, value, dataOffset, count); + var s7data = await RequestTsduAsync(dataToSend, cancellationToken).ConfigureAwait(false); + + ValidateResponseCode((ReadWriteErrorCode)s7data[14]); + } + catch (OperationCanceledException) + { + throw; + } + catch (Exception exc) + { + throw new PlcException(ErrorCode.WriteData, exc); + } + } + + private async Task WriteBitWithASingleRequestAsync(DataType dataType, int db, int startByteAdr, int bitAdr, bool bitValue, CancellationToken cancellationToken) + { + try + { + var dataToSend = BuildWriteBitPackage(dataType, db, startByteAdr, bitValue, bitAdr); + var s7data = await RequestTsduAsync(dataToSend, cancellationToken).ConfigureAwait(false); + + ValidateResponseCode((ReadWriteErrorCode)s7data[14]); + } + catch (OperationCanceledException) + { + throw; + } + catch (Exception exc) + { + throw new PlcException(ErrorCode.WriteData, exc); + } + } + + private Task RequestTsduAsync(byte[] requestData, CancellationToken cancellationToken = default) => + RequestTsduAsync(requestData, 0, requestData.Length, cancellationToken); + + private Task RequestTsduAsync(byte[] requestData, int offset, int length, CancellationToken cancellationToken = default) + { + var stream = GetStreamIfAvailable(); + + return queue.Enqueue(() => + NoLockRequestTsduAsync(stream, requestData, offset, length, cancellationToken)); + } + + private async Task NoLockRequestTpduAsync(Stream stream, byte[] requestData, + CancellationToken cancellationToken = default) + { + cancellationToken.ThrowIfCancellationRequested(); + try + { + using var closeOnCancellation = cancellationToken.Register(Close); + await stream.WriteAsync(requestData, 0, requestData.Length, cancellationToken).ConfigureAwait(false); + return await COTP.TPDU.ReadAsync(stream, cancellationToken).ConfigureAwait(false); + } + catch (Exception exc) + { + if (exc is TPDUInvalidException || exc is TPKTInvalidException) + { + Close(); + } + + throw; + } + } + + private async Task NoLockRequestTsduAsync(Stream stream, byte[] requestData, int offset, int length, + CancellationToken cancellationToken = default) + { + cancellationToken.ThrowIfCancellationRequested(); + try + { + using var closeOnCancellation = cancellationToken.Register(Close); + await stream.WriteAsync(requestData, offset, length, cancellationToken).ConfigureAwait(false); + return await COTP.TSDU.ReadAsync(stream, cancellationToken).ConfigureAwait(false); + } + catch (Exception exc) + { + if (exc is TPDUInvalidException || exc is TPKTInvalidException) + { + Close(); + } + + throw; + } + } + } +} diff --git a/src/Khd.Core.Plc/S7/PlcException.cs b/src/Khd.Core.Plc/S7/PlcException.cs new file mode 100644 index 0000000..0fa473c --- /dev/null +++ b/src/Khd.Core.Plc/S7/PlcException.cs @@ -0,0 +1,37 @@ +namespace Khd.Core.Plc.S7 +{ +#if NET_FULL + [Serializable] +#endif + public class PlcException : Exception + { + public ErrorCode ErrorCode { get; } + + public PlcException(ErrorCode errorCode) : this(errorCode, $"PLC communication failed with error '{errorCode}'.") + { + } + + public PlcException(ErrorCode errorCode, Exception innerException) : this(errorCode, innerException.Message, + innerException) + { + } + + public PlcException(ErrorCode errorCode, string message) : base(message) + { + ErrorCode = errorCode; + } + + public PlcException(ErrorCode errorCode, string message, Exception inner) : base(message, inner) + { + ErrorCode = errorCode; + } + +#if NET_FULL + protected PlcException(System.Runtime.Serialization.SerializationInfo info, + System.Runtime.Serialization.StreamingContext context) : base(info, context) + { + ErrorCode = (ErrorCode) info.GetInt32(nameof(ErrorCode)); + } +#endif + } +} \ No newline at end of file diff --git a/src/Khd.Core.Plc/S7/PlcSynchronous.cs b/src/Khd.Core.Plc/S7/PlcSynchronous.cs new file mode 100644 index 0000000..949850d --- /dev/null +++ b/src/Khd.Core.Plc/S7/PlcSynchronous.cs @@ -0,0 +1,478 @@ +using Khd.Core.Plc.S7.Helper; +using Khd.Core.Plc.S7.Protocol; +using Khd.Core.Plc.S7.Types; + +//Implement synchronous methods here +namespace Khd.Core.Plc.S7 +{ + public partial class Plc + { + /// + /// Connects to the PLC and performs a COTP ConnectionRequest and S7 CommunicationSetup. + /// + public void Open() + { + try + { + OpenAsync().GetAwaiter().GetResult(); + } + catch (Exception exc) + { + throw new PlcException(ErrorCode.ConnectionError, + $"Couldn't establish the connection to {IP}.\nMessage: {exc.Message}", exc); + } + } + + + /// + /// Reads a number of bytes from a DB starting from a specified index. This handles more than 200 bytes with multiple requests. + /// If the read was not successful, check LastErrorCode or LastErrorString. + /// + /// Data type of the memory area, can be DB, Timer, Counter, Merker(Memory), Input, Output. + /// Address of the memory area (if you want to read DB1, this is set to 1). This must be set also for other memory area types: counters, timers,etc. + /// Start byte address. If you want to read DB1.DBW200, this is 200. + /// Byte count, if you want to read 120 bytes, set this to 120. + /// Returns the bytes in an array + public byte[] ReadBytes(DataType dataType, int db, int startByteAdr, int count) + { + var result = new byte[count]; + int index = 0; + while (count > 0) + { + //This works up to MaxPDUSize-1 on SNAP7. But not MaxPDUSize-0. + var maxToRead = Math.Min(count, MaxPDUSize - 18); + ReadBytesWithSingleRequest(dataType, db, startByteAdr + index, result, index, maxToRead); + count -= maxToRead; + index += maxToRead; + } + return result; + } + + /// + /// Read and decode a certain number of bytes of the "VarType" provided. + /// This can be used to read multiple consecutive variables of the same type (Word, DWord, Int, etc). + /// If the read was not successful, check LastErrorCode or LastErrorString. + /// + /// Data type of the memory area, can be DB, Timer, Counter, Merker(Memory), Input, Output. + /// Address of the memory area (if you want to read DB1, this is set to 1). This must be set also for other memory area types: counters, timers,etc. + /// Start byte address. If you want to read DB1.DBW200, this is 200. + /// Type of the variable/s that you are reading + /// Address of bit. If you want to read DB1.DBX200.6, set 6 to this parameter. + /// + public object? Read(DataType dataType, int db, int startByteAdr, VarType varType, int varCount, byte bitAdr = 0) + { + int cntBytes = VarTypeToByteLength(varType, varCount); + byte[] bytes = ReadBytes(dataType, db, startByteAdr, cntBytes); + + return ParseBytes(varType, bytes, varCount, bitAdr); + } + + /// + /// Reads a single variable from the PLC, takes in input strings like "DB1.DBX0.0", "DB20.DBD200", "MB20", "T45", etc. + /// If the read was not successful, check LastErrorCode or LastErrorString. + /// + /// Input strings like "DB1.DBX0.0", "DB20.DBD200", "MB20", "T45", etc. + /// Returns an object that contains the value. This object must be cast accordingly. If no data has been read, null will be returned + public object? Read(string variable) + { + var adr = new PLCAddress(variable); + return Read(adr.DataType, adr.DbNumber, adr.StartByte, adr.VarType, 1, (byte)adr.BitNumber); + } + + public object? Read(string variable, VarType varType) + { + var adr = new PLCAddress(variable); + return Read(adr.DataType, adr.DbNumber, adr.StartByte, varType, 1, (byte)adr.BitNumber); + } + + /// + /// Reads all the bytes needed to fill a struct in C#, starting from a certain address, and return an object that can be casted to the struct. + /// + /// Type of the struct to be readed (es.: TypeOf(MyStruct)). + /// Address of the DB. + /// Start byte address. If you want to read DB1.DBW200, this is 200. + /// Returns a struct that must be cast. If no data has been read, null will be returned + public object? ReadStruct(Type structType, int db, int startByteAdr = 0) + { + int numBytes = Struct.GetStructSize(structType); + // now read the package + var resultBytes = ReadBytes(DataType.DataBlock, db, startByteAdr, numBytes); + + // and decode it + return Struct.FromBytes(structType, resultBytes); + } + + /// + /// Reads all the bytes needed to fill a struct in C#, starting from a certain address, and returns the struct or null if nothing was read. + /// + /// The struct type + /// Address of the DB. + /// Start byte address. If you want to read DB1.DBW200, this is 200. + /// Returns a nullable struct. If nothing was read null will be returned. + public T? ReadStruct(int db, int startByteAdr = 0) where T : struct + { + return ReadStruct(typeof(T), db, startByteAdr) as T?; + } + + + /// + /// Reads all the bytes needed to fill a class in C#, starting from a certain address, and set all the properties values to the value that are read from the PLC. + /// This reads only properties, it doesn't read private variable or public variable without {get;set;} specified. + /// + /// Instance of the class that will store the values + /// Index of the DB; es.: 1 is for DB1 + /// Start byte address. If you want to read DB1.DBW200, this is 200. + /// The number of read bytes + public int ReadClass(object sourceClass, int db, int startByteAdr = 0) + { + int numBytes = (int)Class.GetClassSize(sourceClass); + if (numBytes <= 0) + { + throw new Exception("The size of the class is less than 1 byte and therefore cannot be read"); + } + + // now read the package + var resultBytes = ReadBytes(DataType.DataBlock, db, startByteAdr, numBytes); + // and decode it + Class.FromBytes(sourceClass, resultBytes); + return resultBytes.Length; + } + + /// + /// Reads all the bytes needed to fill a class in C#, starting from a certain address, and set all the properties values to the value that are read from the PLC. + /// This reads only properties, it doesn't read private variable or public variable without {get;set;} specified. To instantiate the class defined by the generic + /// type, the class needs a default constructor. + /// + /// The class that will be instantiated. Requires a default constructor + /// Index of the DB; es.: 1 is for DB1 + /// Start byte address. If you want to read DB1.DBW200, this is 200. + /// An instance of the class with the values read from the PLC. If no data has been read, null will be returned + public T? ReadClass(int db, int startByteAdr = 0) where T : class + { + return ReadClass(() => Activator.CreateInstance(), db, startByteAdr); + } + + /// + /// Reads all the bytes needed to fill a class in C#, starting from a certain address, and set all the properties values to the value that are read from the PLC. + /// This reads only properties, it doesn't read private variable or public variable without {get;set;} specified. + /// + /// The class that will be instantiated + /// Function to instantiate the class + /// Index of the DB; es.: 1 is for DB1 + /// Start byte address. If you want to read DB1.DBW200, this is 200. + /// An instance of the class with the values read from the PLC. If no data has been read, null will be returned + public T? ReadClass(Func classFactory, int db, int startByteAdr = 0) where T : class + { + var instance = classFactory(); + int readBytes = ReadClass(instance, db, startByteAdr); + if (readBytes <= 0) + { + return null; + } + return instance; + } + + /// + /// Write a number of bytes from a DB starting from a specified index. This handles more than 200 bytes with multiple requests. + /// If the write was not successful, check LastErrorCode or LastErrorString. + /// + /// Data type of the memory area, can be DB, Timer, Counter, Merker(Memory), Input, Output. + /// Address of the memory area (if you want to read DB1, this is set to 1). This must be set also for other memory area types: counters, timers,etc. + /// Start byte address. If you want to write DB1.DBW200, this is 200. + /// Bytes to write. If more than 200, multiple requests will be made. + public void WriteBytes(DataType dataType, int db, int startByteAdr, byte[] value) + { + int localIndex = 0; + int count = value.Length; + while (count > 0) + { + //TODO: Figure out how to use MaxPDUSize here + //Snap7 seems to choke on PDU sizes above 256 even if snap7 + //replies with bigger PDU size in connection setup. + var maxToWrite = Math.Min(count, MaxPDUSize - 28);//TODO tested only when the MaxPDUSize is 480 + WriteBytesWithASingleRequest(dataType, db, startByteAdr + localIndex, value, localIndex, maxToWrite); + count -= maxToWrite; + localIndex += maxToWrite; + } + } + + /// + /// Write a single bit from a DB with the specified index. + /// + /// Data type of the memory area, can be DB, Timer, Counter, Merker(Memory), Input, Output. + /// Address of the memory area (if you want to read DB1, this is set to 1). This must be set also for other memory area types: counters, timers,etc. + /// Start byte address. If you want to write DB1.DBW200, this is 200. + /// The address of the bit. (0-7) + /// Bytes to write. If more than 200, multiple requests will be made. + public void WriteBit(DataType dataType, int db, int startByteAdr, int bitAdr, bool value) + { + if (bitAdr < 0 || bitAdr > 7) + throw new InvalidAddressException(string.Format("Addressing Error: You can only reference bitwise locations 0-7. Address {0} is invalid", bitAdr)); + + WriteBitWithASingleRequest(dataType, db, startByteAdr, bitAdr, value); + } + + /// + /// Write a single bit to a DB with the specified index. + /// + /// Data type of the memory area, can be DB, Timer, Counter, Merker(Memory), Input, Output. + /// Address of the memory area (if you want to write DB1, this is set to 1). This must be set also for other memory area types: counters, timers,etc. + /// Start byte address. If you want to write DB1.DBW200, this is 200. + /// The address of the bit. (0-7) + /// Value to write (0 or 1). + public void WriteBit(DataType dataType, int db, int startByteAdr, int bitAdr, int value) + { + if (value < 0 || value > 1) + throw new ArgumentException("Value must be 0 or 1", nameof(value)); + + WriteBit(dataType, db, startByteAdr, bitAdr, value == 1); + } + + /// + /// Takes in input an object and tries to parse it to an array of values. This can be used to write many data, all of the same type. + /// You must specify the memory area type, memory are address, byte start address and bytes count. + /// If the read was not successful, check LastErrorCode or LastErrorString. + /// + /// Data type of the memory area, can be DB, Timer, Counter, Merker(Memory), Input, Output. + /// Address of the memory area (if you want to read DB1, this is set to 1). This must be set also for other memory area types: counters, timers,etc. + /// Start byte address. If you want to read DB1.DBW200, this is 200. + /// Bytes to write. The lenght of this parameter can't be higher than 200. If you need more, use recursion. + /// The address of the bit. (0-7) + public void Write(DataType dataType, int db, int startByteAdr, object value, int bitAdr = -1) + { + if (bitAdr != -1) + { + //Must be writing a bit value as bitAdr is specified + if (value is bool boolean) + { + WriteBit(dataType, db, startByteAdr, bitAdr, boolean); + } + else if (value is int intValue) + { + if (intValue < 0 || intValue > 7) + throw new ArgumentOutOfRangeException( + string.Format( + "Addressing Error: You can only reference bitwise locations 0-7. Address {0} is invalid", + bitAdr), nameof(bitAdr)); + + WriteBit(dataType, db, startByteAdr, bitAdr, intValue == 1); + } + else + throw new ArgumentException("Value must be a bool or an int to write a bit", nameof(value)); + } + else WriteBytes(dataType, db, startByteAdr, Serialization.SerializeValue(value)); + } + + /// + /// Writes a single variable from the PLC, takes in input strings like "DB1.DBX0.0", "DB20.DBD200", "MB20", "T45", etc. + /// If the write was not successful, check or . + /// + /// Input strings like "DB1.DBX0.0", "DB20.DBD200", "MB20", "T45", etc. + /// Value to be written to the PLC + public void Write(string variable, object value) + { + var adr = new PLCAddress(variable); + Write(adr.DataType, adr.DbNumber, adr.StartByte, value, adr.BitNumber); + } + + /// + /// Writes a C# struct to a DB in the PLC + /// + /// The struct to be written + /// Db address + /// Start bytes on the PLC + public void WriteStruct(object structValue, int db, int startByteAdr = 0) + { + WriteStructAsync(structValue, db, startByteAdr).GetAwaiter().GetResult(); + } + + /// + /// Writes a C# class to a DB in the PLC + /// + /// The class to be written + /// Db address + /// Start bytes on the PLC + public void WriteClass(object classValue, int db, int startByteAdr = 0) + { + WriteClassAsync(classValue, db, startByteAdr).GetAwaiter().GetResult(); + } + + private void ReadBytesWithSingleRequest(DataType dataType, int db, int startByteAdr, byte[] buffer, int offset, int count) + { + try + { + // first create the header + int packageSize = 19 + 12; // 19 header + 12 for 1 request + var package = new System.IO.MemoryStream(packageSize); + BuildHeaderPackage(package); + // package.Add(0x02); // datenart + BuildReadDataRequestPackage(package, dataType, db, startByteAdr, count); + + var dataToSend = package.ToArray(); + var s7data = RequestTsdu(dataToSend); + AssertReadResponse(s7data, count); + + Array.Copy(s7data, 18, buffer, offset, count); + } + catch (Exception exc) + { + throw new PlcException(ErrorCode.ReadData, this.IP, exc); + } + } + + /// + /// Write DataItem(s) to the PLC. Throws an exception if the response is invalid + /// or when the PLC reports errors for item(s) written. + /// + /// The DataItem(s) to write to the PLC. + public void Write(params DataItem[] dataItems) + { + AssertPduSizeForWrite(dataItems); + + + var message = new ByteArray(); + var length = S7WriteMultiple.CreateRequest(message, dataItems); + var response = RequestTsdu(message.Array, 0, length); + + S7WriteMultiple.ParseResponse(response, response.Length, dataItems); + } + + private void WriteBytesWithASingleRequest(DataType dataType, int db, int startByteAdr, byte[] value, int dataOffset, int count) + { + try + { + var dataToSend = BuildWriteBytesPackage(dataType, db, startByteAdr, value, dataOffset, count); + var s7data = RequestTsdu(dataToSend); + + ValidateResponseCode((ReadWriteErrorCode)s7data[14]); + } + catch (Exception exc) + { + throw new PlcException(ErrorCode.WriteData, this.IP, exc); + } + } + + private byte[] BuildWriteBytesPackage(DataType dataType, int db, int startByteAdr, byte[] value, int dataOffset, int count) + { + int varCount = count; + // first create the header + int packageSize = 35 + varCount; + var package = new MemoryStream(new byte[packageSize]); + + package.WriteByte(3); + package.WriteByte(0); + //complete package size + package.WriteByteArray(Int.ToByteArray((short)packageSize)); + package.WriteByteArray(new byte[] { 2, 0xf0, 0x80, 0x32, 1, 0, 0 }); + package.WriteByteArray(Word.ToByteArray((ushort)(varCount - 1))); + package.WriteByteArray(new byte[] { 0, 0x0e }); + package.WriteByteArray(Word.ToByteArray((ushort)(varCount + 4))); + package.WriteByteArray(new byte[] { 0x05, 0x01, 0x12, 0x0a, 0x10, 0x02 }); + package.WriteByteArray(Word.ToByteArray((ushort)varCount)); + package.WriteByteArray(Word.ToByteArray((ushort)(db))); + package.WriteByte((byte)dataType); + var overflow = (int)(startByteAdr * 8 / 0xffffU); // handles words with address bigger than 8191 + package.WriteByte((byte)overflow); + package.WriteByteArray(Word.ToByteArray((ushort)(startByteAdr * 8))); + package.WriteByteArray(new byte[] { 0, 4 }); + package.WriteByteArray(Word.ToByteArray((ushort)(varCount * 8))); + + // now join the header and the data + package.Write(value, dataOffset, count); + + return package.ToArray(); + } + + private byte[] BuildWriteBitPackage(DataType dataType, int db, int startByteAdr, bool bitValue, int bitAdr) + { + var value = new[] { bitValue ? (byte)1 : (byte)0 }; + int varCount = 1; + // first create the header + int packageSize = 35 + varCount; + var package = new MemoryStream(new byte[packageSize]); + + package.WriteByte(3); + package.WriteByte(0); + //complete package size + package.WriteByteArray(Int.ToByteArray((short)packageSize)); + package.WriteByteArray(new byte[] { 2, 0xf0, 0x80, 0x32, 1, 0, 0 }); + package.WriteByteArray(Word.ToByteArray((ushort)(varCount - 1))); + package.WriteByteArray(new byte[] { 0, 0x0e }); + package.WriteByteArray(Word.ToByteArray((ushort)(varCount + 4))); + package.WriteByteArray(new byte[] { 0x05, 0x01, 0x12, 0x0a, 0x10, 0x01 }); //ending 0x01 is used for writing a sinlge bit + package.WriteByteArray(Word.ToByteArray((ushort)varCount)); + package.WriteByteArray(Word.ToByteArray((ushort)(db))); + package.WriteByte((byte)dataType); + var overflow = (int)(startByteAdr * 8 / 0xffffU); // handles words with address bigger than 8191 + package.WriteByte((byte)overflow); + package.WriteByteArray(Word.ToByteArray((ushort)(startByteAdr * 8 + bitAdr))); + package.WriteByteArray(new byte[] { 0, 0x03 }); //ending 0x03 is used for writing a sinlge bit + package.WriteByteArray(Word.ToByteArray((ushort)(varCount))); + + // now join the header and the data + package.WriteByteArray(value); + + return package.ToArray(); + } + + + private void WriteBitWithASingleRequest(DataType dataType, int db, int startByteAdr, int bitAdr, bool bitValue) + { + try + { + var dataToSend = BuildWriteBitPackage(dataType, db, startByteAdr, bitValue, bitAdr); + var s7data = RequestTsdu(dataToSend); + + ValidateResponseCode((ReadWriteErrorCode)s7data[14]); + } + catch (Exception exc) + { + throw new PlcException(ErrorCode.WriteData, exc); + } + } + + /// + /// Reads multiple vars in a single request. + /// You have to create and pass a list of DataItems and you obtain in response the same list with the values. + /// Values are stored in the property "Value" of the dataItem and are already converted. + /// If you don't want the conversion, just create a dataItem of bytes. + /// The number of DataItems as well as the total size of the requested data can not exceed a certain limit (protocol restriction). + /// + /// List of dataitems that contains the list of variables that must be read. + public void ReadMultipleVars(List dataItems) + { + AssertPduSizeForRead(dataItems); + + try + { + // first create the header + int packageSize = 19 + (dataItems.Count * 12); + var package = new System.IO.MemoryStream(packageSize); + BuildHeaderPackage(package, dataItems.Count); + // package.Add(0x02); // datenart + foreach (var dataItem in dataItems) + { + BuildReadDataRequestPackage(package, dataItem.DataType, dataItem.DB, dataItem.StartByteAdr, VarTypeToByteLength(dataItem.VarType, dataItem.Count)); + } + + var dataToSend = package.ToArray(); + var s7data = RequestTsdu(dataToSend); + + ValidateResponseCode((ReadWriteErrorCode)s7data[14]); + + ParseDataIntoDataItems(s7data, dataItems); + } + catch (Exception exc) + { + throw new PlcException(ErrorCode.ReadData, exc); + } + } + + private byte[] RequestTsdu(byte[] requestData) => RequestTsdu(requestData, 0, requestData.Length); + + private byte[] RequestTsdu(byte[] requestData, int offset, int length) + { + return RequestTsduAsync(requestData, offset, length).GetAwaiter().GetResult(); + } + } +} diff --git a/src/Khd.Core.Plc/S7/Protocol/ConnectionRequest.cs b/src/Khd.Core.Plc/S7/Protocol/ConnectionRequest.cs new file mode 100644 index 0000000..44b7eb3 --- /dev/null +++ b/src/Khd.Core.Plc/S7/Protocol/ConnectionRequest.cs @@ -0,0 +1,28 @@ +namespace Khd.Core.Plc.S7.Protocol +{ + internal static class ConnectionRequest + { + public static byte[] GetCOTPConnectionRequest(TsapPair tsapPair) + { + byte[] bSend1 = { + 3, 0, 0, 22, //TPKT + 17, //COTP Header Length + 224, //Connect Request + 0, 0, //Destination Reference + 0, 46, //Source Reference + 0, //Flags + 193, //Parameter Code (src-tasp) + 2, //Parameter Length + tsapPair.Local.FirstByte, tsapPair.Local.SecondByte, //Source TASP + 194, //Parameter Code (dst-tasp) + 2, //Parameter Length + tsapPair.Remote.FirstByte, tsapPair.Remote.SecondByte, //Destination TASP + 192, //Parameter Code (tpdu-size) + 1, //Parameter Length + 10 //TPDU Size (2^10 = 1024) + }; + + return bSend1; + } + } +} diff --git a/src/Khd.Core.Plc/S7/Protocol/ReadWriteErrorCode.cs b/src/Khd.Core.Plc/S7/Protocol/ReadWriteErrorCode.cs new file mode 100644 index 0000000..9423780 --- /dev/null +++ b/src/Khd.Core.Plc/S7/Protocol/ReadWriteErrorCode.cs @@ -0,0 +1,15 @@ + +namespace Khd.Core.Plc.S7.Protocol +{ + internal enum ReadWriteErrorCode : byte + { + Reserved = 0x00, + HardwareFault = 0x01, + AccessingObjectNotAllowed = 0x03, + AddressOutOfRange = 0x05, + DataTypeNotSupported = 0x06, + DataTypeInconsistent = 0x07, + ObjectDoesNotExist = 0x0a, + Success = 0xff + } +} diff --git a/src/Khd.Core.Plc/S7/Protocol/S7/DataItemAddress.cs b/src/Khd.Core.Plc/S7/Protocol/S7/DataItemAddress.cs new file mode 100644 index 0000000..f068c32 --- /dev/null +++ b/src/Khd.Core.Plc/S7/Protocol/S7/DataItemAddress.cs @@ -0,0 +1,37 @@ +namespace Khd.Core.Plc.S7.Protocol.S7 +{ + /// + /// Represents an area of memory in the PLC + /// + internal class DataItemAddress + { + public DataItemAddress(DataType dataType, int db, int startByteAddress, int byteLength) + { + DataType = dataType; + DB = db; + StartByteAddress = startByteAddress; + ByteLength = byteLength; + } + + + /// + /// Memory area to read + /// + public DataType DataType { get; } + + /// + /// Address of memory area to read (example: for DB1 this value is 1, for T45 this value is 45) + /// + public int DB { get; } + + /// + /// Address of the first byte to read + /// + public int StartByteAddress { get; } + + /// + /// Length of data to read + /// + public int ByteLength { get; } + } +} diff --git a/src/Khd.Core.Plc/S7/Protocol/S7WriteMultiple.cs b/src/Khd.Core.Plc/S7/Protocol/S7WriteMultiple.cs new file mode 100644 index 0000000..ff92dc9 --- /dev/null +++ b/src/Khd.Core.Plc/S7/Protocol/S7WriteMultiple.cs @@ -0,0 +1,162 @@ +using Khd.Core.Plc.S7.Types; + +namespace Khd.Core.Plc.S7.Protocol +{ + internal static class S7WriteMultiple + { + public static int CreateRequest(ByteArray message, DataItem[] dataItems) + { + message.Add(Header.Template); + + message[Header.Offsets.ParameterCount] = (byte)dataItems.Length; + var paramSize = dataItems.Length * Parameter.Template.Length; + + Serialization.SetWordAt(message, Header.Offsets.ParameterSize, + (ushort)(2 + paramSize)); + + var paramOffset = Header.Template.Length; + var data = new ByteArray(); + + var itemCount = 0; + + foreach (var item in dataItems) + { + itemCount++; + message.Add(Parameter.Template); + var value = Serialization.SerializeDataItem(item); + var wordLen = item.Value is bool ? 1 : 2; + + message[paramOffset + Parameter.Offsets.WordLength] = (byte)wordLen; + Serialization.SetWordAt(message, paramOffset + Parameter.Offsets.Amount, (ushort)value.Length); + Serialization.SetWordAt(message, paramOffset + Parameter.Offsets.DbNumber, (ushort)item.DB); + message[paramOffset + Parameter.Offsets.Area] = (byte)item.DataType; + + data.Add(0x00); + if (item.Value is bool b) + { + if (item.BitAdr > 7) + throw new ArgumentException( + $"Cannot read bit with invalid {nameof(item.BitAdr)} '{item.BitAdr}'.", nameof(dataItems)); + + Serialization.SetAddressAt(message, paramOffset + Parameter.Offsets.Address, item.StartByteAdr, + item.BitAdr); + + data.Add(0x03); + data.AddWord(1); + + data.Add(b ? (byte)1 : (byte)0); + if (itemCount != dataItems.Length) + { + data.Add(0); + } + } + else + { + Serialization.SetAddressAt(message, paramOffset + Parameter.Offsets.Address, item.StartByteAdr, 0); + + var len = value.Length; + data.Add(0x04); + data.AddWord((ushort)(len << 3)); + data.Add(value); + + if ((len & 0b1) == 1 && itemCount != dataItems.Length) + { + data.Add(0); + } + } + + paramOffset += Parameter.Template.Length; + } + + message.Add(data.Array); + + Serialization.SetWordAt(message, Header.Offsets.MessageLength, (ushort)message.Length); + Serialization.SetWordAt(message, Header.Offsets.DataLength, (ushort)(message.Length - paramOffset)); + + return message.Length; + } + + public static void ParseResponse(byte[] message, int length, DataItem[] dataItems) + { + if (length < 12) throw new Exception("Not enough data received to parse write response."); + + var messageError = Serialization.GetWordAt(message, 10); + if (messageError != 0) + throw new Exception($"Write failed with error {messageError}."); + + if (length < 14 + dataItems.Length) + throw new Exception("Not enough data received to parse individual item responses."); + + IList itemResults = new ArraySegment(message, 14, dataItems.Length); + + List? errors = null; + + for (int i = 0; i < dataItems.Length; i++) + { + try + { + Plc.ValidateResponseCode((ReadWriteErrorCode)itemResults[i]); + } + catch (Exception e) + { + if (errors == null) errors = new List(); + errors.Add(new Exception($"Write of dataItem {dataItems[i]} failed: {e.Message}.")); + } + + } + + if (errors != null) + throw new AggregateException( + $"Write failed for {errors.Count} items. See the innerExceptions for details.", errors); + } + + private static class Header + { + public static byte[] Template { get; } = + { + 0x03, 0x00, 0x00, 0x00, // TPKT + 0x02, 0xf0, 0x80, // ISO DT + 0x32, // S7 protocol ID + 0x01, // JobRequest + 0x00, 0x00, // Reserved + 0x05, 0x00, // PDU reference + 0x00, 0x0e, // Parameters length + 0x00, 0x00, // Data length + 0x05, // Function: Write var + 0x00, // Number of items to write + }; + + public static class Offsets + { + public const int MessageLength = 2; + public const int ParameterSize = 13; + public const int DataLength = 15; + public const int ParameterCount = 18; + } + } + + private static class Parameter + { + public static byte[] Template { get; } = + { + 0x12, // Spec + 0x0a, // Length of remaining bytes + 0x10, // Addressing mode + 0x02, // Transport size + 0x00, 0x00, // Number of elements + 0x00, 0x00, // DB number + 0x84, // Area type + 0x00, 0x00, 0x00 // Area offset + }; + + public static class Offsets + { + public const int WordLength = 3; + public const int Amount = 4; + public const int DbNumber = 6; + public const int Area = 8; + public const int Address = 9; + } + } + } +} diff --git a/src/Khd.Core.Plc/S7/Protocol/Serialization.cs b/src/Khd.Core.Plc/S7/Protocol/Serialization.cs new file mode 100644 index 0000000..f0786d5 --- /dev/null +++ b/src/Khd.Core.Plc/S7/Protocol/Serialization.cs @@ -0,0 +1,96 @@ +using Khd.Core.Plc.S7.Types; + +namespace Khd.Core.Plc.S7.Protocol +{ + internal static class Serialization + { + public static ushort GetWordAt(IList buf, int index) + { + return (ushort)((buf[index] << 8) + buf[index]); + } + + public static byte[] SerializeDataItem(DataItem dataItem) + { + if (dataItem.Value == null) + { + throw new Exception($"DataItem.Value is null, cannot serialize. StartAddr={dataItem.StartByteAdr} VarType={dataItem.VarType}"); + } + + if (dataItem.Value is string s) + return dataItem.VarType switch + { + VarType.S7String => S7String.ToByteArray(s, dataItem.Count), + VarType.S7WString => S7WString.ToByteArray(s, dataItem.Count), + _ => Types.String.ToByteArray(s, dataItem.Count) + }; + + return SerializeValue(dataItem.Value); + } + + public static byte[] SerializeValue(object value) + { + switch (value.GetType().Name) + { + case "Boolean": + return new[] { (byte)((bool)value ? 1 : 0) }; + case "Byte": + return Types.Byte.ToByteArray((byte)value); + case "Int16": + return Types.Int.ToByteArray((Int16)value); + case "UInt16": + return Types.Word.ToByteArray((UInt16)value); + case "Int32": + return Types.DInt.ToByteArray((Int32)value); + case "UInt32": + return Types.DWord.ToByteArray((UInt32)value); + case "Single": + return Types.Real.ToByteArray((float)value); + case "Double": + return Types.LReal.ToByteArray((double)value); + case "DateTime": + return Types.DateTime.ToByteArray((System.DateTime)value); + case "Byte[]": + return (byte[])value; + case "Int16[]": + return Types.Int.ToByteArray((Int16[])value); + case "UInt16[]": + return Types.Word.ToByteArray((UInt16[])value); + case "Int32[]": + return Types.DInt.ToByteArray((Int32[])value); + case "UInt32[]": + return Types.DWord.ToByteArray((UInt32[])value); + case "Single[]": + return Types.Real.ToByteArray((float[])value); + case "Double[]": + return Types.LReal.ToByteArray((double[])value); + case "String": + // Hack: This is backwards compatible with the old code, but functionally it's broken + // if the consumer does not pay attention to string length. + var stringVal = (string)value; + return Types.String.ToByteArray(stringVal, stringVal.Length); + case "DateTime[]": + return Types.DateTime.ToByteArray((System.DateTime[])value); + case "DateTimeLong[]": + return Types.DateTimeLong.ToByteArray((System.DateTime[])value); + default: + throw new InvalidVariableTypeException(); + } + } + + public static void SetAddressAt(ByteArray buffer, int index, int startByte, byte bitNumber) + { + var start = startByte * 8 + bitNumber; + buffer[index + 2] = (byte)start; + start >>= 8; + buffer[index + 1] = (byte)start; + start >>= 8; + buffer[index] = (byte)start; + } + + public static void SetWordAt(ByteArray buffer, int index, ushort value) + { + buffer[index] = (byte)(value >> 8); + buffer[index + 1] = (byte)value; + } + } +} diff --git a/src/Khd.Core.Plc/S7/Protocol/Tsap.cs b/src/Khd.Core.Plc/S7/Protocol/Tsap.cs new file mode 100644 index 0000000..35293b6 --- /dev/null +++ b/src/Khd.Core.Plc/S7/Protocol/Tsap.cs @@ -0,0 +1,31 @@ +namespace Khd.Core.Plc.S7.Protocol +{ + /// + /// Provides a representation of the Transport Service Access Point, or TSAP in short. TSAP's are used + /// to specify a client and server address. For most PLC types a default TSAP is available that allows + /// connection from any IP and can be calculated using the rack and slot numbers. + /// + public struct Tsap + { + /// + /// First byte of the TSAP. + /// + public byte FirstByte { get; set; } + + /// + /// Second byte of the TSAP. + /// + public byte SecondByte { get; set; } + + /// + /// Initializes a new instance of the class using the specified values. + /// + /// The first byte of the TSAP. + /// The second byte of the TSAP. + public Tsap(byte firstByte, byte secondByte) + { + FirstByte = firstByte; + SecondByte = secondByte; + } + } +} \ No newline at end of file diff --git a/src/Khd.Core.Plc/S7/Protocol/TsapPair.cs b/src/Khd.Core.Plc/S7/Protocol/TsapPair.cs new file mode 100644 index 0000000..dcf8365 --- /dev/null +++ b/src/Khd.Core.Plc/S7/Protocol/TsapPair.cs @@ -0,0 +1,94 @@ +namespace Khd.Core.Plc.S7.Protocol +{ + /// + /// Implements a pair of TSAP addresses used to connect to a PLC. + /// + public class TsapPair + { + /// + /// The local . + /// + public Tsap Local { get; set; } + + /// + /// The remote + /// + public Tsap Remote { get; set; } + + /// + /// Initializes a new instance of the class using the specified local and + /// remote TSAP. + /// + /// The local TSAP. + /// The remote TSAP. + public TsapPair(Tsap local, Tsap remote) + { + Local = local; + Remote = remote; + } + + /// + /// Builds a that can be used to connect to a PLC using the default connection + /// addresses. + /// + /// + /// The remote TSAP is constructed using new Tsap(0x03, (byte) ((rack << 5) | slot)). + /// + /// The CPU type of the PLC. + /// The rack of the PLC's network card. + /// The slot of the PLC's network card. + /// A TSAP pair that matches the given parameters. + /// The is invalid. + /// + /// -or- + /// + /// The parameter is less than 0. + /// + /// -or- + /// + /// The parameter is greater than 15. + /// + /// -or- + /// + /// The parameter is less than 0. + /// + /// -or- + /// + /// The parameter is greater than 15. + public static TsapPair GetDefaultTsapPair(CpuType cpuType, int rack, int slot) + { + if (rack < 0) throw InvalidRackOrSlot(rack, nameof(rack), "minimum", 0); + if (rack > 0x0F) throw InvalidRackOrSlot(rack, nameof(rack), "maximum", 0x0F); + + if (slot < 0) throw InvalidRackOrSlot(slot, nameof(slot), "minimum", 0); + if (slot > 0x0F) throw InvalidRackOrSlot(slot, nameof(slot), "maximum", 0x0F); + + switch (cpuType) + { + case CpuType.S7200: + return new TsapPair(new Tsap(0x10, 0x00), new Tsap(0x10, 0x01)); + case CpuType.Logo0BA8: + // The actual values are probably on a per-project basis + return new TsapPair(new Tsap(0x01, 0x00), new Tsap(0x01, 0x02)); + case CpuType.S7200Smart: + case CpuType.S71200: + case CpuType.S71500: + case CpuType.S7300: + case CpuType.S7400: + // Testing with S7 1500 shows only the remote TSAP needs to match. This might differ for other + // PLC types. + return new TsapPair(new Tsap(0x01, 0x00), new Tsap(0x03, (byte)((rack << 5) | slot))); + default: + throw new ArgumentOutOfRangeException(nameof(cpuType), "Invalid CPU Type specified"); + } + } + + private static ArgumentOutOfRangeException InvalidRackOrSlot(int value, string name, string extrema, + int extremaValue) + { + return new ArgumentOutOfRangeException(name, + $"Invalid {name} value specified (decimal: {value}, hexadecimal: {value:X}), {extrema} value " + + $"is {extremaValue} (decimal) or {extremaValue:X} (hexadecimal)."); + } + } +} \ No newline at end of file diff --git a/src/Khd.Core.Plc/S7/SiPLC.cs b/src/Khd.Core.Plc/S7/SiPLC.cs new file mode 100644 index 0000000..9d126c3 --- /dev/null +++ b/src/Khd.Core.Plc/S7/SiPLC.cs @@ -0,0 +1,63 @@ +using HslCommunication.Profinet.Siemens; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace RainTest.Helper +{ + public class SiPLC + { + private SiemensS7Net PLC = new SiemensS7Net(SiemensPLCS.S200Smart); + private Random dom = new Random(); + public string IP { get; set; } + public bool Open() + { + PLC.IpAddress = IP; + return PLC.ConnectServer().IsSuccess; + } + public float ReadFloat(string address) + { + //var test = PLC.ReadFloat("M0.7"); + return PLC.ReadFloat(address).Content; + } + /// + /// 用这个方法试试 + /// + /// + /// + public bool ReadBool(string address) + { + return PLC.ReadBool(address).Content; + } + public bool ReadWord(string address) + { + return PLC.ReadBool(address).Content; + } + public HslCommunication.OperateResult WriteFloat(string address,float value) + { + return PLC.Write(address,value); + } + public HslCommunication.OperateResult WriteFloat1(string address, float value) + { + float test = value / 1000; + return PLC.Write(address, test); + } + public HslCommunication.OperateResult WriteFloat(string address, bool value) + { + return PLC.Write(address, value); + } + public bool Close() + { + try + { + return PLC.ConnectClose().IsSuccess; + } + catch(Exception ex) + { + } + return true; + } + } +} diff --git a/src/Khd.Core.Plc/S7/StreamExtensions.cs b/src/Khd.Core.Plc/S7/StreamExtensions.cs new file mode 100644 index 0000000..6175e8e --- /dev/null +++ b/src/Khd.Core.Plc/S7/StreamExtensions.cs @@ -0,0 +1,52 @@ +namespace Khd.Core.Plc.S7 +{ + /// + /// Extensions for Streams + /// + public static class StreamExtensions + { + /// + /// Reads bytes from the stream into the buffer until exactly the requested number of bytes (or EOF) have been read + /// + /// the Stream to read from + /// the buffer to read into + /// the offset in the buffer to read into + /// the amount of bytes to read into the buffer + /// returns the amount of read bytes + public static int ReadExact(this Stream stream, byte[] buffer, int offset, int count) + { + int read = 0; + int received; + do + { + received = stream.Read(buffer, offset + read, count - read); + read += received; + } + while (read < count && received > 0); + + return read; + } + + /// + /// Reads bytes from the stream into the buffer until exactly the requested number of bytes (or EOF) have been read + /// + /// the Stream to read from + /// the buffer to read into + /// the offset in the buffer to read into + /// the amount of bytes to read into the buffer + /// returns the amount of read bytes + public static async Task ReadExactAsync(this Stream stream, byte[] buffer, int offset, int count, CancellationToken cancellationToken) + { + int read = 0; + int received; + do + { + received = await stream.ReadAsync(buffer, offset + read, count - read, cancellationToken).ConfigureAwait(false); + read += received; + } + while (read < count && received > 0); + + return read; + } + } +} \ No newline at end of file diff --git a/src/Khd.Core.Plc/S7/TPKT.cs b/src/Khd.Core.Plc/S7/TPKT.cs new file mode 100644 index 0000000..fb1e345 --- /dev/null +++ b/src/Khd.Core.Plc/S7/TPKT.cs @@ -0,0 +1,61 @@ +namespace Khd.Core.Plc.S7 +{ + + /// + /// Describes a TPKT Packet + /// + internal class TPKT + { + + + public byte Version; + public byte Reserved1; + public int Length; + public byte[] Data; + private TPKT(byte version, byte reserved1, int length, byte[] data) + { + Version = version; + Reserved1 = reserved1; + Length = length; + Data = data; + } + + /// + /// Reads a TPKT from the socket Async + /// + /// The stream to read from + /// Task TPKT Instace + public static async Task ReadAsync(Stream stream, CancellationToken cancellationToken) + { + var buf = new byte[4]; + int len = await stream.ReadExactAsync(buf, 0, 4, cancellationToken).ConfigureAwait(false); + if (len < 4) throw new TPKTInvalidException("TPKT is incomplete / invalid"); + + var version = buf[0]; + var reserved1 = buf[1]; + var length = buf[2] * 256 + buf[3]; //BigEndian + + var data = new byte[length - 4]; + len = await stream.ReadExactAsync(data, 0, data.Length, cancellationToken).ConfigureAwait(false); + if (len < data.Length) + throw new TPKTInvalidException("TPKT payload incomplete / invalid"); + + return new TPKT + ( + version: version, + reserved1: reserved1, + length: length, + data: data + ); + } + + public override string ToString() + { + return string.Format("Version: {0} Length: {1} Data: {2}", + Version, + Length, + BitConverter.ToString(Data) + ); + } + } +} diff --git a/src/Khd.Core.Plc/S7/Types/Bit.cs b/src/Khd.Core.Plc/S7/Types/Bit.cs new file mode 100644 index 0000000..98f86f6 --- /dev/null +++ b/src/Khd.Core.Plc/S7/Types/Bit.cs @@ -0,0 +1,42 @@ +using System.Collections; + +namespace Khd.Core.Plc.S7.Types +{ + /// + /// Contains the conversion methods to convert Bit from S7 plc to C#. + /// + public static class Bit + { + /// + /// Converts a Bit to bool + /// + public static bool FromByte(byte v, byte bitAdr) + { + return (((int)v & (1 << bitAdr)) != 0); + } + + /// + /// Converts an array of bytes to a BitArray. + /// + /// The bytes to convert. + /// A BitArray with the same number of bits and equal values as . + public static BitArray ToBitArray(byte[] bytes) => ToBitArray(bytes, bytes.Length * 8); + + /// + /// Converts an array of bytes to a BitArray. + /// + /// The bytes to convert. + /// The number of bits to return. + /// A BitArray with bits. + public static BitArray ToBitArray(byte[] bytes, int length) + { + if (length > bytes.Length * 8) throw new ArgumentException($"Not enough data in bytes to return {length} bits.", nameof(bytes)); + + var bitArr = new BitArray(bytes); + var bools = new bool[length]; + for (var i = 0; i < length; i++) bools[i] = bitArr[i]; + + return new BitArray(bools); + } + } +} diff --git a/src/Khd.Core.Plc/S7/Types/Boolean.cs b/src/Khd.Core.Plc/S7/Types/Boolean.cs new file mode 100644 index 0000000..cb89962 --- /dev/null +++ b/src/Khd.Core.Plc/S7/Types/Boolean.cs @@ -0,0 +1,64 @@ +namespace Khd.Core.Plc.S7.Types +{ + /// + /// Contains the methods to read, set and reset bits inside bytes + /// + public static class Boolean + { + /// + /// Returns the value of a bit in a bit, given the address of the bit + /// + public static bool GetValue(byte value, int bit) + { + return (((int)value & (1 << bit)) != 0); + } + + /// + /// Sets the value of a bit to 1 (true), given the address of the bit. Returns + /// a copy of the value with the bit set. + /// + /// The input value to modify. + /// The index (zero based) of the bit to set. + /// The modified value with the bit at index set. + public static byte SetBit(byte value, int bit) + { + SetBit(ref value, bit); + + return value; + } + + /// + /// Sets the value of a bit to 1 (true), given the address of the bit. + /// + /// The value to modify. + /// The index (zero based) of the bit to set. + public static void SetBit(ref byte value, int bit) + { + value = (byte)((value | (1 << bit)) & 0xFF); + } + + /// + /// Resets the value of a bit to 0 (false), given the address of the bit. Returns + /// a copy of the value with the bit cleared. + /// + /// The input value to modify. + /// The index (zero based) of the bit to clear. + /// The modified value with the bit at index cleared. + public static byte ClearBit(byte value, int bit) + { + ClearBit(ref value, bit); + + return value; + } + + /// + /// Resets the value of a bit to 0 (false), given the address of the bit + /// + /// The input value to modify. + /// The index (zero based) of the bit to clear. + public static void ClearBit(ref byte value, int bit) + { + value = (byte)(value & ~(1 << bit) & 0xFF); + } + } +} diff --git a/src/Khd.Core.Plc/S7/Types/Byte.cs b/src/Khd.Core.Plc/S7/Types/Byte.cs new file mode 100644 index 0000000..eb4c88c --- /dev/null +++ b/src/Khd.Core.Plc/S7/Types/Byte.cs @@ -0,0 +1,31 @@ +namespace Khd.Core.Plc.S7.Types +{ + /// + /// Contains the methods to convert from bytes to byte arrays + /// + public static class Byte + { + /// + /// Converts a byte to byte array + /// + public static byte[] ToByteArray(byte value) + { + return new byte[] { value }; ; + } + + /// + /// Converts a byte array to byte + /// + /// + /// + public static byte FromByteArray(byte[] bytes) + { + if (bytes.Length != 1) + { + throw new ArgumentException("Wrong number of bytes. Bytes array must contain 1 bytes."); + } + return bytes[0]; + } + + } +} diff --git a/src/Khd.Core.Plc/S7/Types/ByteArray.cs b/src/Khd.Core.Plc/S7/Types/ByteArray.cs new file mode 100644 index 0000000..d2c195e --- /dev/null +++ b/src/Khd.Core.Plc/S7/Types/ByteArray.cs @@ -0,0 +1,61 @@ +namespace Khd.Core.Plc.S7.Types +{ + class ByteArray + { + List list = new List(); + + public byte this[int index] + { + get => list[index]; + set => list[index] = value; + } + + public byte[] Array + { + get { return list.ToArray(); } + } + + public int Length => list.Count; + + public ByteArray() + { + list = new List(); + } + + public ByteArray(int size) + { + list = new List(size); + } + + public void Clear() + { + list = new List(); + } + + public void Add(byte item) + { + list.Add(item); + } + + public void AddWord(ushort value) + { + list.Add((byte)(value >> 8)); + list.Add((byte)value); + } + + public void Add(byte[] items) + { + list.AddRange(items); + } + + public void Add(IEnumerable items) + { + list.AddRange(items); + } + + public void Add(ByteArray byteArray) + { + list.AddRange(byteArray.Array); + } + } +} diff --git a/src/Khd.Core.Plc/S7/Types/Class.cs b/src/Khd.Core.Plc/S7/Types/Class.cs new file mode 100644 index 0000000..ad49a7c --- /dev/null +++ b/src/Khd.Core.Plc/S7/Types/Class.cs @@ -0,0 +1,337 @@ +using System.Reflection; + +namespace Khd.Core.Plc.S7.Types +{ + /// + /// Contains the methods to convert a C# class to S7 data types + /// + public static class Class + { + private static IEnumerable GetAccessableProperties(Type classType) + { + return classType +#if NETSTANDARD1_3 + .GetTypeInfo().DeclaredProperties.Where(p => p.SetMethod != null); +#else + .GetProperties( + BindingFlags.SetProperty | + BindingFlags.Public | + BindingFlags.Instance) + .Where(p => p.GetSetMethod() != null); +#endif + + } + + private static double GetIncreasedNumberOfBytes(double numBytes, Type type) + { + switch (type.Name) + { + case "Boolean": + numBytes += 0.125; + break; + case "Byte": + numBytes = Math.Ceiling(numBytes); + numBytes++; + break; + case "Int16": + case "UInt16": + numBytes = Math.Ceiling(numBytes); + if ((numBytes / 2 - Math.Floor(numBytes / 2.0)) > 0) + numBytes++; + numBytes += 2; + break; + case "Int32": + case "UInt32": + numBytes = Math.Ceiling(numBytes); + if ((numBytes / 2 - Math.Floor(numBytes / 2.0)) > 0) + numBytes++; + numBytes += 4; + break; + case "Single": + numBytes = Math.Ceiling(numBytes); + if ((numBytes / 2 - Math.Floor(numBytes / 2.0)) > 0) + numBytes++; + numBytes += 4; + break; + case "Double": + numBytes = Math.Ceiling(numBytes); + if ((numBytes / 2 - Math.Floor(numBytes / 2.0)) > 0) + numBytes++; + numBytes += 8; + break; + default: + var propertyClass = Activator.CreateInstance(type); + numBytes = GetClassSize(propertyClass, numBytes, true); + break; + } + + return numBytes; + } + + /// + /// Gets the size of the class in bytes. + /// + /// An instance of the class + /// the number of bytes + public static double GetClassSize(object instance, double numBytes = 0.0, bool isInnerProperty = false) + { + var properties = GetAccessableProperties(instance.GetType()); + foreach (var property in properties) + { + if (property.PropertyType.IsArray) + { + Type elementType = property.PropertyType.GetElementType(); + Array array = (Array)property.GetValue(instance, null); + if (array.Length <= 0) + { + throw new Exception("Cannot determine size of class, because an array is defined which has no fixed size greater than zero."); + } + + IncrementToEven(ref numBytes); + for (int i = 0; i < array.Length; i++) + { + numBytes = GetIncreasedNumberOfBytes(numBytes, elementType); + } + } + else + { + numBytes = GetIncreasedNumberOfBytes(numBytes, property.PropertyType); + } + } + if (false == isInnerProperty) + { + // enlarge numBytes to next even number because S7-Structs in a DB always will be resized to an even byte count + numBytes = Math.Ceiling(numBytes); + if ((numBytes / 2 - Math.Floor(numBytes / 2.0)) > 0) + numBytes++; + } + return numBytes; + } + + private static object? GetPropertyValue(Type propertyType, byte[] bytes, ref double numBytes) + { + object? value = null; + + switch (propertyType.Name) + { + case "Boolean": + // get the value + int bytePos = (int)Math.Floor(numBytes); + int bitPos = (int)((numBytes - (double)bytePos) / 0.125); + if ((bytes[bytePos] & (int)Math.Pow(2, bitPos)) != 0) + value = true; + else + value = false; + numBytes += 0.125; + break; + case "Byte": + numBytes = Math.Ceiling(numBytes); + value = (byte)(bytes[(int)numBytes]); + numBytes++; + break; + case "Int16": + numBytes = Math.Ceiling(numBytes); + if ((numBytes / 2 - Math.Floor(numBytes / 2.0)) > 0) + numBytes++; + // hier auswerten + ushort source = Word.FromBytes(bytes[(int)numBytes + 1], bytes[(int)numBytes]); + value = source.ConvertToShort(); + numBytes += 2; + break; + case "UInt16": + numBytes = Math.Ceiling(numBytes); + if ((numBytes / 2 - Math.Floor(numBytes / 2.0)) > 0) + numBytes++; + // hier auswerten + value = Word.FromBytes(bytes[(int)numBytes + 1], bytes[(int)numBytes]); + numBytes += 2; + break; + case "Int32": + numBytes = Math.Ceiling(numBytes); + if ((numBytes / 2 - Math.Floor(numBytes / 2.0)) > 0) + numBytes++; + // hier auswerten + uint sourceUInt = DWord.FromBytes(bytes[(int)numBytes + 3], + bytes[(int)numBytes + 2], + bytes[(int)numBytes + 1], + bytes[(int)numBytes + 0]); + value = sourceUInt.ConvertToInt(); + numBytes += 4; + break; + case "UInt32": + numBytes = Math.Ceiling(numBytes); + if ((numBytes / 2 - Math.Floor(numBytes / 2.0)) > 0) + numBytes++; + // hier auswerten + value = DWord.FromBytes( + bytes[(int)numBytes], + bytes[(int)numBytes + 1], + bytes[(int)numBytes + 2], + bytes[(int)numBytes + 3]); + numBytes += 4; + break; + case "Single": + numBytes = Math.Ceiling(numBytes); + if ((numBytes / 2 - Math.Floor(numBytes / 2.0)) > 0) + numBytes++; + // hier auswerten + value = Real.FromByteArray( + new byte[] { + bytes[(int)numBytes], + bytes[(int)numBytes + 1], + bytes[(int)numBytes + 2], + bytes[(int)numBytes + 3] }); + numBytes += 4; + break; + case "Double": + numBytes = Math.Ceiling(numBytes); + if ((numBytes / 2 - Math.Floor(numBytes / 2.0)) > 0) + numBytes++; + var buffer = new byte[8]; + Array.Copy(bytes, (int)numBytes, buffer, 0, 8); + // hier auswerten + value = LReal.FromByteArray(buffer); + numBytes += 8; + break; + default: + var propClass = Activator.CreateInstance(propertyType); + numBytes = FromBytes(propClass, bytes, numBytes); + value = propClass; + break; + } + + return value; + } + + /// + /// Sets the object's values with the given array of bytes + /// + /// The object to fill in the given array of bytes + /// The array of bytes + public static double FromBytes(object sourceClass, byte[] bytes, double numBytes = 0, bool isInnerClass = false) + { + if (bytes == null) + return numBytes; + + var properties = GetAccessableProperties(sourceClass.GetType()); + foreach (var property in properties) + { + if (property.PropertyType.IsArray) + { + Array array = (Array)property.GetValue(sourceClass, null); + IncrementToEven(ref numBytes); + Type elementType = property.PropertyType.GetElementType(); + for (int i = 0; i < array.Length && numBytes < bytes.Length; i++) + { + array.SetValue( + GetPropertyValue(elementType, bytes, ref numBytes), + i); + } + } + else + { + property.SetValue( + sourceClass, + GetPropertyValue(property.PropertyType, bytes, ref numBytes), + null); + } + } + + return numBytes; + } + + private static double SetBytesFromProperty(object propertyValue, byte[] bytes, double numBytes) + { + int bytePos = 0; + int bitPos = 0; + byte[]? bytes2 = null; + + switch (propertyValue.GetType().Name) + { + case "Boolean": + // get the value + bytePos = (int)Math.Floor(numBytes); + bitPos = (int)((numBytes - (double)bytePos) / 0.125); + if ((bool)propertyValue) + bytes[bytePos] |= (byte)Math.Pow(2, bitPos); // is true + else + bytes[bytePos] &= (byte)(~(byte)Math.Pow(2, bitPos)); // is false + numBytes += 0.125; + break; + case "Byte": + numBytes = (int)Math.Ceiling(numBytes); + bytePos = (int)numBytes; + bytes[bytePos] = (byte)propertyValue; + numBytes++; + break; + case "Int16": + bytes2 = Int.ToByteArray((Int16)propertyValue); + break; + case "UInt16": + bytes2 = Word.ToByteArray((UInt16)propertyValue); + break; + case "Int32": + bytes2 = DInt.ToByteArray((Int32)propertyValue); + break; + case "UInt32": + bytes2 = DWord.ToByteArray((UInt32)propertyValue); + break; + case "Single": + bytes2 = Real.ToByteArray((float)propertyValue); + break; + case "Double": + bytes2 = LReal.ToByteArray((double)propertyValue); + break; + default: + numBytes = ToBytes(propertyValue, bytes, numBytes); + break; + } + + if (bytes2 != null) + { + IncrementToEven(ref numBytes); + + bytePos = (int)numBytes; + for (int bCnt = 0; bCnt < bytes2.Length; bCnt++) + bytes[bytePos + bCnt] = bytes2[bCnt]; + numBytes += bytes2.Length; + } + + return numBytes; + } + + /// + /// Creates a byte array depending on the struct type. + /// + /// The struct object + /// A byte array or null if fails. + public static double ToBytes(object sourceClass, byte[] bytes, double numBytes = 0.0) + { + var properties = GetAccessableProperties(sourceClass.GetType()); + foreach (var property in properties) + { + if (property.PropertyType.IsArray) + { + Array array = (Array)property.GetValue(sourceClass, null); + IncrementToEven(ref numBytes); + Type elementType = property.PropertyType.GetElementType(); + for (int i = 0; i < array.Length && numBytes < bytes.Length; i++) + { + numBytes = SetBytesFromProperty(array.GetValue(i), bytes, numBytes); + } + } + else + { + numBytes = SetBytesFromProperty(property.GetValue(sourceClass, null), bytes, numBytes); + } + } + return numBytes; + } + + private static void IncrementToEven(ref double numBytes) + { + numBytes = Math.Ceiling(numBytes); + if (numBytes % 2 > 0) numBytes++; + } + } +} diff --git a/src/Khd.Core.Plc/S7/Types/Counter.cs b/src/Khd.Core.Plc/S7/Types/Counter.cs new file mode 100644 index 0000000..39b95cb --- /dev/null +++ b/src/Khd.Core.Plc/S7/Types/Counter.cs @@ -0,0 +1,61 @@ +namespace Khd.Core.Plc.S7.Types +{ + /// + /// Contains the conversion methods to convert Counter from S7 plc to C# ushort (UInt16). + /// + public static class Counter + { + /// + /// Converts a Counter (2 bytes) to ushort (UInt16) + /// + public static UInt16 FromByteArray(byte[] bytes) + { + if (bytes.Length != 2) + { + throw new ArgumentException("Wrong number of bytes. Bytes array must contain 2 bytes."); + } + // bytes[0] -> HighByte + // bytes[1] -> LowByte + return (UInt16)((bytes[0] << 8) | bytes[1]); + } + + + /// + /// Converts a ushort (UInt16) to word (2 bytes) + /// + public static byte[] ToByteArray(UInt16 value) + { + byte[] bytes = new byte[2]; + + bytes[0] = (byte)((value << 8) & 0xFF); + bytes[1] = (byte)((value) & 0xFF); + + return bytes; + } + + /// + /// Converts an array of ushort (UInt16) to an array of bytes + /// + public static byte[] ToByteArray(UInt16[] value) + { + ByteArray arr = new ByteArray(); + foreach (UInt16 val in value) + arr.Add(ToByteArray(val)); + return arr.Array; + } + + /// + /// Converts an array of bytes to an array of ushort + /// + public static UInt16[] ToArray(byte[] bytes) + { + UInt16[] values = new UInt16[bytes.Length / 2]; + + int counter = 0; + for (int cnt = 0; cnt < bytes.Length / 2; cnt++) + values[cnt] = FromByteArray(new byte[] { bytes[counter++], bytes[counter++] }); + + return values; + } + } +} diff --git a/src/Khd.Core.Plc/S7/Types/DInt.cs b/src/Khd.Core.Plc/S7/Types/DInt.cs new file mode 100644 index 0000000..9a51ba5 --- /dev/null +++ b/src/Khd.Core.Plc/S7/Types/DInt.cs @@ -0,0 +1,63 @@ +namespace Khd.Core.Plc.S7.Types +{ + /// + /// Contains the conversion methods to convert DInt from S7 plc to C# int (Int32). + /// + public static class DInt + { + /// + /// Converts a S7 DInt (4 bytes) to int (Int32) + /// + public static Int32 FromByteArray(byte[] bytes) + { + if (bytes.Length != 4) + { + throw new ArgumentException("Wrong number of bytes. Bytes array must contain 4 bytes."); + } + return bytes[0] << 24 | bytes[1] << 16 | bytes[2] << 8 | bytes[3]; + } + + + /// + /// Converts a int (Int32) to S7 DInt (4 bytes) + /// + public static byte[] ToByteArray(Int32 value) + { + byte[] bytes = new byte[4]; + + bytes[0] = (byte)((value >> 24) & 0xFF); + bytes[1] = (byte)((value >> 16) & 0xFF); + bytes[2] = (byte)((value >> 8) & 0xFF); + bytes[3] = (byte)((value) & 0xFF); + + return bytes; + } + + /// + /// Converts an array of int (Int32) to an array of bytes + /// + public static byte[] ToByteArray(Int32[] value) + { + ByteArray arr = new ByteArray(); + foreach (Int32 val in value) + arr.Add(ToByteArray(val)); + return arr.Array; + } + + /// + /// Converts an array of S7 DInt to an array of int (Int32) + /// + public static Int32[] ToArray(byte[] bytes) + { + Int32[] values = new Int32[bytes.Length / 4]; + + int counter = 0; + for (int cnt = 0; cnt < bytes.Length / 4; cnt++) + values[cnt] = FromByteArray(new byte[] { bytes[counter++], bytes[counter++], bytes[counter++], bytes[counter++] }); + + return values; + } + + + } +} diff --git a/src/Khd.Core.Plc/S7/Types/DWord.cs b/src/Khd.Core.Plc/S7/Types/DWord.cs new file mode 100644 index 0000000..f96e36e --- /dev/null +++ b/src/Khd.Core.Plc/S7/Types/DWord.cs @@ -0,0 +1,71 @@ +namespace Khd.Core.Plc.S7.Types +{ + /// + /// Contains the conversion methods to convert DWord from S7 plc to C#. + /// + public static class DWord + { + /// + /// Converts a S7 DWord (4 bytes) to uint (UInt32) + /// + public static UInt32 FromByteArray(byte[] bytes) + { + return (UInt32)(bytes[0] << 24 | bytes[1] << 16 | bytes[2] << 8 | bytes[3]); + } + + + /// + /// Converts 4 bytes to DWord (UInt32) + /// + public static UInt32 FromBytes(byte b1, byte b2, byte b3, byte b4) + { + return (UInt32)((b4 << 24) | (b3 << 16) | (b2 << 8) | b1); + } + + + /// + /// Converts a uint (UInt32) to S7 DWord (4 bytes) + /// + public static byte[] ToByteArray(UInt32 value) + { + byte[] bytes = new byte[4]; + + bytes[0] = (byte)((value >> 24) & 0xFF); + bytes[1] = (byte)((value >> 16) & 0xFF); + bytes[2] = (byte)((value >> 8) & 0xFF); + bytes[3] = (byte)((value) & 0xFF); + + return bytes; + } + + + + + + + /// + /// Converts an array of uint (UInt32) to an array of S7 DWord (4 bytes) + /// + public static byte[] ToByteArray(UInt32[] value) + { + ByteArray arr = new ByteArray(); + foreach (UInt32 val in value) + arr.Add(ToByteArray(val)); + return arr.Array; + } + + /// + /// Converts an array of S7 DWord to an array of uint (UInt32) + /// + public static UInt32[] ToArray(byte[] bytes) + { + UInt32[] values = new UInt32[bytes.Length / 4]; + + int counter = 0; + for (int cnt = 0; cnt < bytes.Length / 4; cnt++) + values[cnt] = FromByteArray(new byte[] { bytes[counter++], bytes[counter++], bytes[counter++], bytes[counter++] }); + + return values; + } + } +} diff --git a/src/Khd.Core.Plc/S7/Types/DataItem.cs b/src/Khd.Core.Plc/S7/Types/DataItem.cs new file mode 100644 index 0000000..c326b80 --- /dev/null +++ b/src/Khd.Core.Plc/S7/Types/DataItem.cs @@ -0,0 +1,103 @@ +using Khd.Core.Plc.S7.Protocol.S7; + +namespace Khd.Core.Plc.S7.Types +{ + /// + /// Create an instance of a memory block that can be read by using ReadMultipleVars + /// + public class DataItem + { + /// + /// Memory area to read + /// + public DataType DataType { get; set; } + + /// + /// Type of data to be read (default is bytes) + /// + public VarType VarType { get; set; } + + /// + /// Address of memory area to read (example: for DB1 this value is 1, for T45 this value is 45) + /// + public int DB { get; set; } + + /// + /// Address of the first byte to read + /// + public int StartByteAdr { get; set; } + + /// + /// Addess of bit to read from StartByteAdr + /// + public byte BitAdr { get; set; } + + /// + /// Number of variables to read + /// + public int Count { get; set; } + + /// + /// Contains the value of the memory area after the read has been executed + /// + public object? Value { get; set; } + + /// + /// Create an instance of DataItem + /// + public DataItem() + { + VarType = VarType.Byte; + Count = 1; + } + + /// + /// Create an instance of from the supplied address. + /// + /// The address to create the DataItem for. + /// A new instance with properties parsed from . + /// The property is not parsed from the address. + public static DataItem FromAddress(string address) + { + PLCAddress.Parse(address, out var dataType, out var dbNumber, out var varType, out var startByte, + out var bitNumber); + + return new DataItem + { + DataType = dataType, + DB = dbNumber, + VarType = varType, + StartByteAdr = startByte, + BitAdr = (byte)(bitNumber == -1 ? 0 : bitNumber) + }; + } + + /// + /// Create an instance of from the supplied address and value. + /// + /// The address to create the DataItem for. + /// The value to be applied to the DataItem. + /// A new instance with properties parsed from and the supplied value set. + public static DataItem FromAddressAndValue(string address, T value) + { + var dataItem = FromAddress(address); + dataItem.Value = value; + + if (typeof(T).IsArray) + { + var array = ((Array?)dataItem.Value); + if (array != null) + { + dataItem.Count = array.Length; + } + } + + return dataItem; + } + + internal static DataItemAddress GetDataItemAddress(DataItem dataItem) + { + return new DataItemAddress(dataItem.DataType, dataItem.DB, dataItem.StartByteAdr, Plc.VarTypeToByteLength(dataItem.VarType, dataItem.Count)); + } + } +} diff --git a/src/Khd.Core.Plc/S7/Types/DateTime.cs b/src/Khd.Core.Plc/S7/Types/DateTime.cs new file mode 100644 index 0000000..57e8535 --- /dev/null +++ b/src/Khd.Core.Plc/S7/Types/DateTime.cs @@ -0,0 +1,153 @@ +namespace Khd.Core.Plc.S7.Types +{ + /// + /// Contains the methods to convert between and S7 representation of datetime values. + /// + public static class DateTime + { + /// + /// The minimum value supported by the specification. + /// + public static readonly System.DateTime SpecMinimumDateTime = new System.DateTime(1990, 1, 1); + + /// + /// The maximum value supported by the specification. + /// + public static readonly System.DateTime SpecMaximumDateTime = new System.DateTime(2089, 12, 31, 23, 59, 59, 999); + + /// + /// Parses a value from bytes. + /// + /// Input bytes read from PLC. + /// A object representing the value read from PLC. + /// Thrown when the length of + /// is not 8 or any value in + /// is outside the valid range of values. + public static System.DateTime FromByteArray(byte[] bytes) + { + return FromByteArrayImpl(bytes); + } + + /// + /// Parses an array of values from bytes. + /// + /// Input bytes read from PLC. + /// An array of objects representing the values read from PLC. + /// Thrown when the length of + /// is not a multiple of 8 or any value in + /// is outside the valid range of values. + public static System.DateTime[] ToArray(byte[] bytes) + { + if (bytes.Length % 8 != 0) + throw new ArgumentOutOfRangeException(nameof(bytes), bytes.Length, + $"Parsing an array of DateTime requires a multiple of 8 bytes of input data, input data is '{bytes.Length}' long."); + + var cnt = bytes.Length / 8; + var result = new System.DateTime[bytes.Length / 8]; + + for (var i = 0; i < cnt; i++) + result[i] = FromByteArrayImpl(new ArraySegment(bytes, i * 8, 8)); + + return result; + } + + private static System.DateTime FromByteArrayImpl(IList bytes) + { + if (bytes.Count != 8) + throw new ArgumentOutOfRangeException(nameof(bytes), bytes.Count, + $"Parsing a DateTime requires exactly 8 bytes of input data, input data is {bytes.Count} bytes long."); + + int DecodeBcd(byte input) => 10 * (input >> 4) + (input & 0b00001111); + + int ByteToYear(byte bcdYear) + { + var input = DecodeBcd(bcdYear); + if (input < 90) return input + 2000; + if (input < 100) return input + 1900; + + throw new ArgumentOutOfRangeException(nameof(bcdYear), bcdYear, + $"Value '{input}' is higher than the maximum '99' of S7 date and time representation."); + } + + int AssertRangeInclusive(int input, byte min, byte max, string field) + { + if (input < min) + throw new ArgumentOutOfRangeException(nameof(input), input, + $"Value '{input}' is lower than the minimum '{min}' allowed for {field}."); + if (input > max) + throw new ArgumentOutOfRangeException(nameof(input), input, + $"Value '{input}' is higher than the maximum '{max}' allowed for {field}."); + + return input; + } + + var year = ByteToYear(bytes[0]); + var month = AssertRangeInclusive(DecodeBcd(bytes[1]), 1, 12, "month"); + var day = AssertRangeInclusive(DecodeBcd(bytes[2]), 1, 31, "day of month"); + var hour = AssertRangeInclusive(DecodeBcd(bytes[3]), 0, 23, "hour"); + var minute = AssertRangeInclusive(DecodeBcd(bytes[4]), 0, 59, "minute"); + var second = AssertRangeInclusive(DecodeBcd(bytes[5]), 0, 59, "second"); + var hsec = AssertRangeInclusive(DecodeBcd(bytes[6]), 0, 99, "first two millisecond digits"); + var msec = AssertRangeInclusive(bytes[7] >> 4, 0, 9, "third millisecond digit"); + var dayOfWeek = AssertRangeInclusive(bytes[7] & 0b00001111, 1, 7, "day of week"); + + return new System.DateTime(year, month, day, hour, minute, second, hsec * 10 + msec); + } + + /// + /// Converts a value to a byte array. + /// + /// The DateTime value to convert. + /// A byte array containing the S7 date time representation of . + /// Thrown when the value of + /// is before + /// or after . + public static byte[] ToByteArray(System.DateTime dateTime) + { + byte EncodeBcd(int value) + { + return (byte)((value / 10 << 4) | value % 10); + } + + if (dateTime < SpecMinimumDateTime) + throw new ArgumentOutOfRangeException(nameof(dateTime), dateTime, + $"Date time '{dateTime}' is before the minimum '{SpecMinimumDateTime}' supported in S7 date time representation."); + + if (dateTime > SpecMaximumDateTime) + throw new ArgumentOutOfRangeException(nameof(dateTime), dateTime, + $"Date time '{dateTime}' is after the maximum '{SpecMaximumDateTime}' supported in S7 date time representation."); + + byte MapYear(int year) => (byte)(year < 2000 ? year - 1900 : year - 2000); + + int DayOfWeekToInt(DayOfWeek dayOfWeek) => (int)dayOfWeek + 1; + + return new[] + { + EncodeBcd(MapYear(dateTime.Year)), + EncodeBcd(dateTime.Month), + EncodeBcd(dateTime.Day), + EncodeBcd(dateTime.Hour), + EncodeBcd(dateTime.Minute), + EncodeBcd(dateTime.Second), + EncodeBcd(dateTime.Millisecond / 10), + (byte) (dateTime.Millisecond % 10 << 4 | DayOfWeekToInt(dateTime.DayOfWeek)) + }; + } + + /// + /// Converts an array of values to a byte array. + /// + /// The DateTime values to convert. + /// A byte array containing the S7 date time representations of . + /// Thrown when any value of + /// is before + /// or after . + public static byte[] ToByteArray(System.DateTime[] dateTimes) + { + var bytes = new List(dateTimes.Length * 8); + foreach (var dateTime in dateTimes) bytes.AddRange(ToByteArray(dateTime)); + + return bytes.ToArray(); + } + } +} \ No newline at end of file diff --git a/src/Khd.Core.Plc/S7/Types/DateTimeLong.cs b/src/Khd.Core.Plc/S7/Types/DateTimeLong.cs new file mode 100644 index 0000000..eb677ce --- /dev/null +++ b/src/Khd.Core.Plc/S7/Types/DateTimeLong.cs @@ -0,0 +1,181 @@ +namespace Khd.Core.Plc.S7.Types +{ + /// + /// Contains the methods to convert between and S7 representation of DateTimeLong (DTL) values. + /// + public static class DateTimeLong + { + public const int TypeLengthInBytes = 12; + /// + /// The minimum value supported by the specification. + /// + public static readonly System.DateTime SpecMinimumDateTime = new System.DateTime(1970, 1, 1); + + /// + /// The maximum value supported by the specification. + /// + public static readonly System.DateTime SpecMaximumDateTime = new System.DateTime(2262, 4, 11, 23, 47, 16, 854); + + /// + /// Parses a value from bytes. + /// + /// Input bytes read from PLC. + /// A object representing the value read from PLC. + /// + /// Thrown when the length of + /// is not 12 or any value in + /// is outside the valid range of values. + /// + public static System.DateTime FromByteArray(byte[] bytes) + { + return FromByteArrayImpl(bytes); + } + + /// + /// Parses an array of values from bytes. + /// + /// Input bytes read from PLC. + /// An array of objects representing the values read from PLC. + /// + /// Thrown when the length of + /// is not a multiple of 12 or any value in + /// is outside the valid range of values. + /// + public static System.DateTime[] ToArray(byte[] bytes) + { + if (bytes.Length % TypeLengthInBytes != 0) + { + throw new ArgumentOutOfRangeException(nameof(bytes), bytes.Length, + $"Parsing an array of DateTimeLong requires a multiple of 12 bytes of input data, input data is '{bytes.Length}' long."); + } + + var cnt = bytes.Length / TypeLengthInBytes; + var result = new System.DateTime[cnt]; + + for (var i = 0; i < cnt; i++) + { + var slice = new byte[TypeLengthInBytes]; + Array.Copy(bytes, i * TypeLengthInBytes, slice, 0, TypeLengthInBytes); + result[i] = FromByteArrayImpl(slice); + } + + return result; + } + + private static System.DateTime FromByteArrayImpl(byte[] bytes) + { + if (bytes.Length != TypeLengthInBytes) + { + throw new ArgumentOutOfRangeException(nameof(bytes), bytes.Length, + $"Parsing a DateTimeLong requires exactly 12 bytes of input data, input data is {bytes.Length} bytes long."); + } + + + var year = AssertRangeInclusive(Word.FromBytes(bytes[1], bytes[0]), 1970, 2262, "year"); + var month = AssertRangeInclusive(bytes[2], 1, 12, "month"); + var day = AssertRangeInclusive(bytes[3], 1, 31, "day of month"); + var dayOfWeek = AssertRangeInclusive(bytes[4], 1, 7, "day of week"); + var hour = AssertRangeInclusive(bytes[5], 0, 23, "hour"); + var minute = AssertRangeInclusive(bytes[6], 0, 59, "minute"); + var second = AssertRangeInclusive(bytes[7], 0, 59, "second"); + ; + + var nanoseconds = AssertRangeInclusive(DWord.FromBytes(bytes[11], bytes[10], bytes[9], bytes[8]), 0, + 999999999, "nanoseconds"); + + var time = new System.DateTime(year, month, day, hour, minute, second); + return time.AddTicks(nanoseconds / 100); + } + + /// + /// Converts a value to a byte array. + /// + /// The DateTime value to convert. + /// A byte array containing the S7 DateTimeLong representation of . + /// + /// Thrown when the value of + /// is before + /// or after . + /// + public static byte[] ToByteArray(System.DateTime dateTime) + { + if (dateTime < SpecMinimumDateTime) + { + throw new ArgumentOutOfRangeException(nameof(dateTime), dateTime, + $"Date time '{dateTime}' is before the minimum '{SpecMinimumDateTime}' supported in S7 DateTimeLong representation."); + } + + if (dateTime > SpecMaximumDateTime) + { + throw new ArgumentOutOfRangeException(nameof(dateTime), dateTime, + $"Date time '{dateTime}' is after the maximum '{SpecMaximumDateTime}' supported in S7 DateTimeLong representation."); + } + + var stream = new MemoryStream(TypeLengthInBytes); + // Convert Year + stream.Write(Word.ToByteArray(Convert.ToUInt16(dateTime.Year)), 0, 2); + + // Convert Month + stream.WriteByte(Convert.ToByte(dateTime.Month)); + + // Convert Day + stream.WriteByte(Convert.ToByte(dateTime.Day)); + + // Convert WeekDay. NET DateTime starts with Sunday = 0, while S7DT has Sunday = 1. + stream.WriteByte(Convert.ToByte(dateTime.DayOfWeek + 1)); + + // Convert Hour + stream.WriteByte(Convert.ToByte(dateTime.Hour)); + + // Convert Minutes + stream.WriteByte(Convert.ToByte(dateTime.Minute)); + + // Convert Seconds + stream.WriteByte(Convert.ToByte(dateTime.Second)); + + // Convert Nanoseconds. Net DateTime has a representation of 1 Tick = 100ns. + // Thus First take the ticks Mod 1 Second (1s = 10'000'000 ticks), and then Convert to nanoseconds. + stream.Write(DWord.ToByteArray(Convert.ToUInt32(dateTime.Ticks % 10000000 * 100)), 0, 4); + + return stream.ToArray(); + } + + /// + /// Converts an array of values to a byte array. + /// + /// The DateTime values to convert. + /// A byte array containing the S7 DateTimeLong representations of . + /// + /// Thrown when any value of + /// is before + /// or after . + /// + public static byte[] ToByteArray(System.DateTime[] dateTimes) + { + var bytes = new List(dateTimes.Length * TypeLengthInBytes); + foreach (var dateTime in dateTimes) + { + bytes.AddRange(ToByteArray(dateTime)); + } + + return bytes.ToArray(); + } + + private static T AssertRangeInclusive(T input, T min, T max, string field) where T : IComparable + { + if (input.CompareTo(min) < 0) + { + throw new ArgumentOutOfRangeException(nameof(input), input, + $"Value '{input}' is lower than the minimum '{min}' allowed for {field}."); + } + + if (input.CompareTo(max) > 0) + { + throw new ArgumentOutOfRangeException(nameof(input), input, + $"Value '{input}' is higher than the maximum '{max}' allowed for {field}."); + } + + return input; + } + } +} \ No newline at end of file diff --git a/src/Khd.Core.Plc/S7/Types/Double.cs b/src/Khd.Core.Plc/S7/Types/Double.cs new file mode 100644 index 0000000..42fbd6c --- /dev/null +++ b/src/Khd.Core.Plc/S7/Types/Double.cs @@ -0,0 +1,66 @@ +namespace Khd.Core.Plc.S7.Types +{ + /// + /// Contains the conversion methods to convert Real from S7 plc to C# double. + /// + [Obsolete("Class Double is obsolete. Use Real instead for 32bit floating point, or LReal for 64bit floating point.")] + public static class Double + { + /// + /// Converts a S7 Real (4 bytes) to double + /// + public static double FromByteArray(byte[] bytes) => Real.FromByteArray(bytes); + + /// + /// Converts a S7 DInt to double + /// + public static double FromDWord(Int32 value) + { + byte[] b = DInt.ToByteArray(value); + double d = FromByteArray(b); + return d; + } + + /// + /// Converts a S7 DWord to double + /// + public static double FromDWord(UInt32 value) + { + byte[] b = DWord.ToByteArray(value); + double d = FromByteArray(b); + return d; + } + + + /// + /// Converts a double to S7 Real (4 bytes) + /// + public static byte[] ToByteArray(double value) => Real.ToByteArray((float)value); + + /// + /// Converts an array of double to an array of bytes + /// + public static byte[] ToByteArray(double[] value) + { + ByteArray arr = new ByteArray(); + foreach (double val in value) + arr.Add(ToByteArray(val)); + return arr.Array; + } + + /// + /// Converts an array of S7 Real to an array of double + /// + public static double[] ToArray(byte[] bytes) + { + double[] values = new double[bytes.Length / 4]; + + int counter = 0; + for (int cnt = 0; cnt < bytes.Length / 4; cnt++) + values[cnt] = FromByteArray(new byte[] { bytes[counter++], bytes[counter++], bytes[counter++], bytes[counter++] }); + + return values; + } + + } +} diff --git a/src/Khd.Core.Plc/S7/Types/Int.cs b/src/Khd.Core.Plc/S7/Types/Int.cs new file mode 100644 index 0000000..7c7abed --- /dev/null +++ b/src/Khd.Core.Plc/S7/Types/Int.cs @@ -0,0 +1,85 @@ +namespace Khd.Core.Plc.S7.Types +{ + /// + /// Contains the conversion methods to convert Int from S7 plc to C#. + /// + public static class Int + { + /// + /// Converts a S7 Int (2 bytes) to short (Int16) + /// + public static short FromByteArray(byte[] bytes) + { + if (bytes.Length != 2) + { + throw new ArgumentException("Wrong number of bytes. Bytes array must contain 2 bytes."); + } + // bytes[0] -> HighByte + // bytes[1] -> LowByte + return (short)((int)(bytes[1]) | ((int)(bytes[0]) << 8)); + } + + + /// + /// Converts a short (Int16) to a S7 Int byte array (2 bytes) + /// + public static byte[] ToByteArray(Int16 value) + { + byte[] bytes = new byte[2]; + + bytes[0] = (byte)(value >> 8 & 0xFF); + bytes[1] = (byte)(value & 0xFF); + + return bytes; + } + + /// + /// Converts an array of short (Int16) to a S7 Int byte array (2 bytes) + /// + public static byte[] ToByteArray(Int16[] value) + { + byte[] bytes = new byte[value.Length * 2]; + int bytesPos = 0; + + for (int i = 0; i < value.Length; i++) + { + bytes[bytesPos++] = (byte)((value[i] >> 8) & 0xFF); + bytes[bytesPos++] = (byte)(value[i] & 0xFF); + } + return bytes; + } + + /// + /// Converts an array of S7 Int to an array of short (Int16) + /// + public static Int16[] ToArray(byte[] bytes) + { + int shortsCount = bytes.Length / 2; + + Int16[] values = new Int16[shortsCount]; + + int counter = 0; + for (int cnt = 0; cnt < shortsCount; cnt++) + values[cnt] = FromByteArray(new byte[] { bytes[counter++], bytes[counter++] }); + + return values; + } + + /// + /// Converts a C# int value to a C# short value, to be used as word. + /// + /// + /// + public static Int16 CWord(int value) + { + if (value > 32767) + { + value -= 32768; + value = 32768 - value; + value *= -1; + } + return (short)value; + } + + } +} diff --git a/src/Khd.Core.Plc/S7/Types/LReal.cs b/src/Khd.Core.Plc/S7/Types/LReal.cs new file mode 100644 index 0000000..8d3ffc5 --- /dev/null +++ b/src/Khd.Core.Plc/S7/Types/LReal.cs @@ -0,0 +1,54 @@ +namespace Khd.Core.Plc.S7.Types +{ + /// + /// Contains the conversion methods to convert Real from S7 plc to C# double. + /// + public static class LReal + { + /// + /// Converts a S7 LReal (8 bytes) to double + /// + public static double FromByteArray(byte[] bytes) + { + if (bytes.Length != 8) + { + throw new ArgumentException("Wrong number of bytes. Bytes array must contain 8 bytes."); + } + var buffer = bytes; + + // sps uses bigending so we have to reverse if platform needs + if (BitConverter.IsLittleEndian) + { + Array.Reverse(buffer); + } + + return BitConverter.ToDouble(buffer, 0); + } + + /// + /// Converts a double to S7 LReal (8 bytes) + /// + public static byte[] ToByteArray(double value) + { + var bytes = BitConverter.GetBytes(value); + + // sps uses bigending so we have to check if platform is same + if (BitConverter.IsLittleEndian) + { + Array.Reverse(bytes); + } + return bytes; + } + + /// + /// Converts an array of double to an array of bytes + /// + public static byte[] ToByteArray(double[] value) => TypeHelper.ToByteArray(value, ToByteArray); + + /// + /// Converts an array of S7 LReal to an array of double + /// + public static double[] ToArray(byte[] bytes) => TypeHelper.ToArray(bytes, FromByteArray); + + } +} diff --git a/src/Khd.Core.Plc/S7/Types/Real.cs b/src/Khd.Core.Plc/S7/Types/Real.cs new file mode 100644 index 0000000..375ae6d --- /dev/null +++ b/src/Khd.Core.Plc/S7/Types/Real.cs @@ -0,0 +1,72 @@ +namespace Khd.Core.Plc.S7.Types +{ + /// + /// Contains the conversion methods to convert Real from S7 plc to C# double. + /// + public static class Real + { + /// + /// Converts a S7 Real (4 bytes) to float + /// + public static float FromByteArray(byte[] bytes) + { + if (bytes.Length != 4) + { + throw new ArgumentException("Wrong number of bytes. Bytes array must contain 4 bytes."); + } + + // sps uses bigending so we have to reverse if platform needs + if (BitConverter.IsLittleEndian) + { + // create deep copy of the array and reverse + bytes = new byte[] { bytes[3], bytes[2], bytes[1], bytes[0] }; + } + + return BitConverter.ToSingle(bytes, 0); + } + + /// + /// Converts a float to S7 Real (4 bytes) + /// + public static byte[] ToByteArray(float value) + { + byte[] bytes = BitConverter.GetBytes(value); + + // sps uses bigending so we have to check if platform is same + if (!BitConverter.IsLittleEndian) return bytes; + + // create deep copy of the array and reverse + return new byte[] { bytes[3], bytes[2], bytes[1], bytes[0] }; + } + + /// + /// Converts an array of float to an array of bytes + /// + public static byte[] ToByteArray(float[] value) + { + var buffer = new byte[4 * value.Length]; + var stream = new MemoryStream(buffer); + foreach (var val in value) + { + stream.Write(ToByteArray(val), 0, 4); + } + + return buffer; + } + + /// + /// Converts an array of S7 Real to an array of float + /// + public static float[] ToArray(byte[] bytes) + { + var values = new float[bytes.Length / 4]; + + int counter = 0; + for (int cnt = 0; cnt < bytes.Length / 4; cnt++) + values[cnt] = FromByteArray(new byte[] { bytes[counter++], bytes[counter++], bytes[counter++], bytes[counter++] }); + + return values; + } + + } +} diff --git a/src/Khd.Core.Plc/S7/Types/S7String.cs b/src/Khd.Core.Plc/S7/Types/S7String.cs new file mode 100644 index 0000000..2a4eb8d --- /dev/null +++ b/src/Khd.Core.Plc/S7/Types/S7String.cs @@ -0,0 +1,68 @@ +using System.Text; + +namespace Khd.Core.Plc.S7.Types +{ + /// + /// Contains the methods to convert from S7 strings to C# strings + /// An S7 String has a preceeding 2 byte header containing its capacity and length + /// + public static class S7String + { + /// + /// Converts S7 bytes to a string + /// + /// + /// + public static string FromByteArray(byte[] bytes) + { + if (bytes.Length < 2) + { + throw new PlcException(ErrorCode.ReadData, "Malformed S7 String / too short"); + } + + int size = bytes[0]; + int length = bytes[1]; + if (length > size) + { + throw new PlcException(ErrorCode.ReadData, "Malformed S7 String / length larger than capacity"); + } + + try + { + return Encoding.ASCII.GetString(bytes, 2, length); + } + catch (Exception e) + { + throw new PlcException(ErrorCode.ReadData, + $"Failed to parse {VarType.S7String} from data. Following fields were read: size: '{size}', actual length: '{length}', total number of bytes (including header): '{bytes.Length}'.", + e); + } + + } + + /// + /// Converts a to S7 string with 2-byte header. + /// + /// The string to convert to byte array. + /// The length (in characters) allocated in PLC for the string. + /// A containing the string header and string value with a maximum length of + 2. + public static byte[] ToByteArray(string value, int reservedLength) + { + if (value is null) + { + throw new ArgumentNullException(nameof(value)); + } + + if (reservedLength > 254) throw new ArgumentException($"The maximum string length supported is 254."); + + var bytes = Encoding.ASCII.GetBytes(value); + if (bytes.Length > reservedLength) throw new ArgumentException($"The provided string length ({bytes.Length} is larger than the specified reserved length ({reservedLength})."); + + var buffer = new byte[2 + reservedLength]; + Array.Copy(bytes, 0, buffer, 2, bytes.Length); + buffer[0] = (byte)reservedLength; + buffer[1] = (byte)bytes.Length; + return buffer; + } + } +} diff --git a/src/Khd.Core.Plc/S7/Types/S7StringAttribute.cs b/src/Khd.Core.Plc/S7/Types/S7StringAttribute.cs new file mode 100644 index 0000000..2e4dd8a --- /dev/null +++ b/src/Khd.Core.Plc/S7/Types/S7StringAttribute.cs @@ -0,0 +1,65 @@ +namespace Khd.Core.Plc.S7.Types +{ + [AttributeUsage(AttributeTargets.Field, AllowMultiple = false)] + public sealed class S7StringAttribute : Attribute + { + private readonly S7StringType type; + private readonly int reservedLength; + + /// + /// Initializes a new instance of the class. + /// + /// The string type. + /// Reserved length of the string in characters. + /// Please use a valid value for the string type + public S7StringAttribute(S7StringType type, int reservedLength) + { + if (!Enum.IsDefined(typeof(S7StringType), type)) + throw new ArgumentException("Please use a valid value for the string type"); + + this.type = type; + this.reservedLength = reservedLength; + } + + /// + /// Gets the type of the string. + /// + /// + /// The string type. + /// + public S7StringType Type => type; + + /// + /// Gets the reserved length of the string in characters. + /// + /// + /// The reserved length of the string in characters. + /// + public int ReservedLength => reservedLength; + + /// + /// Gets the reserved length in bytes. + /// + /// + /// The reserved length in bytes. + /// + public int ReservedLengthInBytes => type == S7StringType.S7String ? reservedLength + 2 : (reservedLength * 2) + 4; + } + + + /// + /// String type. + /// + public enum S7StringType + { + /// + /// ASCII string. + /// + S7String = VarType.S7String, + + /// + /// Unicode string. + /// + S7WString = VarType.S7WString + } +} diff --git a/src/Khd.Core.Plc/S7/Types/S7WString.cs b/src/Khd.Core.Plc/S7/Types/S7WString.cs new file mode 100644 index 0000000..78c45f6 --- /dev/null +++ b/src/Khd.Core.Plc/S7/Types/S7WString.cs @@ -0,0 +1,71 @@ +using System.Text; + +namespace Khd.Core.Plc.S7.Types +{ + /// + /// Contains the methods to convert from S7 wstrings to C# strings + /// An S7 WString has a preceding 4 byte header containing its capacity and length + /// + public static class S7WString + { + /// + /// Converts S7 bytes to a string + /// + /// + /// + public static string FromByteArray(byte[] bytes) + { + if (bytes.Length < 4) + { + throw new PlcException(ErrorCode.ReadData, "Malformed S7 WString / too short"); + } + + int size = (bytes[0] << 8) | bytes[1]; + int length = (bytes[2] << 8) | bytes[3]; + + if (length > size) + { + throw new PlcException(ErrorCode.ReadData, "Malformed S7 WString / length larger than capacity"); + } + + try + { + return Encoding.BigEndianUnicode.GetString(bytes, 4, length * 2); + } + catch (Exception e) + { + throw new PlcException(ErrorCode.ReadData, + $"Failed to parse {VarType.S7WString} from data. Following fields were read: size: '{size}', actual length: '{length}', total number of bytes (including header): '{bytes.Length}'.", + e); + } + + } + + /// + /// Converts a to S7 wstring with 4-byte header. + /// + /// The string to convert to byte array. + /// The length (in characters) allocated in PLC for the string. + /// A containing the string header and string value with a maximum length of + 4. + public static byte[] ToByteArray(string value, int reservedLength) + { + if (value is null) + { + throw new ArgumentNullException(nameof(value)); + } + + if (reservedLength > 16382) throw new ArgumentException("The maximum string length supported is 16382."); + + var buffer = new byte[4 + reservedLength * 2]; + buffer[0] = (byte)((reservedLength >> 8) & 0xFF); + buffer[1] = (byte)(reservedLength & 0xFF); + buffer[2] = (byte)((value.Length >> 8) & 0xFF); + buffer[3] = (byte)(value.Length & 0xFF); + + var stringLength = Encoding.BigEndianUnicode.GetBytes(value, 0, value.Length, buffer, 4) / 2; + if (stringLength > reservedLength) throw new ArgumentException($"The provided string length ({stringLength} is larger than the specified reserved length ({reservedLength})."); + + return buffer; + } + } +} diff --git a/src/Khd.Core.Plc/S7/Types/Single.cs b/src/Khd.Core.Plc/S7/Types/Single.cs new file mode 100644 index 0000000..0ee9415 --- /dev/null +++ b/src/Khd.Core.Plc/S7/Types/Single.cs @@ -0,0 +1,66 @@ +namespace Khd.Core.Plc.S7.Types +{ + /// + /// Contains the conversion methods to convert Real from S7 plc to C# float. + /// + [Obsolete("Class Single is obsolete. Use Real instead.")] + public static class Single + { + /// + /// Converts a S7 Real (4 bytes) to float + /// + public static float FromByteArray(byte[] bytes) => Real.FromByteArray(bytes); + + /// + /// Converts a S7 DInt to float + /// + public static float FromDWord(Int32 value) + { + byte[] b = DInt.ToByteArray(value); + float d = FromByteArray(b); + return d; + } + + /// + /// Converts a S7 DWord to float + /// + public static float FromDWord(UInt32 value) + { + byte[] b = DWord.ToByteArray(value); + float d = FromByteArray(b); + return d; + } + + + /// + /// Converts a double to S7 Real (4 bytes) + /// + public static byte[] ToByteArray(float value) => Real.ToByteArray(value); + + /// + /// Converts an array of float to an array of bytes + /// + public static byte[] ToByteArray(float[] value) + { + ByteArray arr = new ByteArray(); + foreach (float val in value) + arr.Add(ToByteArray(val)); + return arr.Array; + } + + /// + /// Converts an array of S7 Real to an array of float + /// + public static float[] ToArray(byte[] bytes) + { + float[] values = new float[bytes.Length / 4]; + + int counter = 0; + for (int cnt = 0; cnt < bytes.Length / 4; cnt++) + values[cnt] = FromByteArray(new byte[] { bytes[counter++], bytes[counter++], bytes[counter++], bytes[counter++] }); + + return values; + } + + } +} diff --git a/src/Khd.Core.Plc/S7/Types/String.cs b/src/Khd.Core.Plc/S7/Types/String.cs new file mode 100644 index 0000000..b7e8b09 --- /dev/null +++ b/src/Khd.Core.Plc/S7/Types/String.cs @@ -0,0 +1,37 @@ +namespace Khd.Core.Plc.S7.Types +{ + /// + /// Contains the methods to convert from S7 Array of Chars (like a const char[N] C-String) to C# strings + /// + public class String + { + /// + /// Converts a string to of bytes, padded with 0-bytes if required. + /// + /// The string to write to the PLC. + /// The amount of bytes reserved for the in the PLC. + public static byte[] ToByteArray(string value, int reservedLength) + { + var length = value?.Length; + if (length > reservedLength) length = reservedLength; + var bytes = new byte[reservedLength]; + + if (length == null || length == 0) return bytes; + + System.Text.Encoding.ASCII.GetBytes(value, 0, length.Value, bytes, 0); + + return bytes; + } + + /// + /// Converts S7 bytes to a string + /// + /// + /// + public static string FromByteArray(byte[] bytes) + { + return System.Text.Encoding.ASCII.GetString(bytes); + } + + } +} diff --git a/src/Khd.Core.Plc/S7/Types/StringEx.cs b/src/Khd.Core.Plc/S7/Types/StringEx.cs new file mode 100644 index 0000000..eefe07c --- /dev/null +++ b/src/Khd.Core.Plc/S7/Types/StringEx.cs @@ -0,0 +1,13 @@ +namespace Khd.Core.Plc.S7.Types +{ + /// + [Obsolete("Please use S7String class")] + public static class StringEx + { + /// + public static string FromByteArray(byte[] bytes) => S7String.FromByteArray(bytes); + + /// + public static byte[] ToByteArray(string value, int reservedLength) => S7String.ToByteArray(value, reservedLength); + } +} diff --git a/src/Khd.Core.Plc/S7/Types/Struct.cs b/src/Khd.Core.Plc/S7/Types/Struct.cs new file mode 100644 index 0000000..bf03144 --- /dev/null +++ b/src/Khd.Core.Plc/S7/Types/Struct.cs @@ -0,0 +1,320 @@ +using System.Reflection; + +namespace Khd.Core.Plc.S7.Types +{ + /// + /// Contains the method to convert a C# struct to S7 data types + /// + public static class Struct + { + /// + /// Gets the size of the struct in bytes. + /// + /// the type of the struct + /// the number of bytes + public static int GetStructSize(Type structType) + { + double numBytes = 0.0; + + var infos = structType +#if NETSTANDARD1_3 + .GetTypeInfo().DeclaredFields; +#else + .GetFields(); +#endif + + foreach (var info in infos) + { + switch (info.FieldType.Name) + { + case "Boolean": + numBytes += 0.125; + break; + case "Byte": + numBytes = Math.Ceiling(numBytes); + numBytes++; + break; + case "Int16": + case "UInt16": + numBytes = Math.Ceiling(numBytes); + if ((numBytes / 2 - Math.Floor(numBytes / 2.0)) > 0) + numBytes++; + numBytes += 2; + break; + case "Int32": + case "UInt32": + numBytes = Math.Ceiling(numBytes); + if ((numBytes / 2 - Math.Floor(numBytes / 2.0)) > 0) + numBytes++; + numBytes += 4; + break; + case "Single": + numBytes = Math.Ceiling(numBytes); + if ((numBytes / 2 - Math.Floor(numBytes / 2.0)) > 0) + numBytes++; + numBytes += 4; + break; + case "Double": + numBytes = Math.Ceiling(numBytes); + if ((numBytes / 2 - Math.Floor(numBytes / 2.0)) > 0) + numBytes++; + numBytes += 8; + break; + case "String": + S7StringAttribute? attribute = info.GetCustomAttributes().SingleOrDefault(); + if (attribute == default(S7StringAttribute)) + throw new ArgumentException("Please add S7StringAttribute to the string field"); + + numBytes = Math.Ceiling(numBytes); + if ((numBytes / 2 - Math.Floor(numBytes / 2.0)) > 0) + numBytes++; + numBytes += attribute.ReservedLengthInBytes; + break; + default: + numBytes += GetStructSize(info.FieldType); + break; + } + } + return (int)numBytes; + } + + /// + /// Creates a struct of a specified type by an array of bytes. + /// + /// The struct type + /// The array of bytes + /// The object depending on the struct type or null if fails(array-length != struct-length + public static object? FromBytes(Type structType, byte[] bytes) + { + if (bytes == null) + return null; + + if (bytes.Length != GetStructSize(structType)) + return null; + + // and decode it + int bytePos = 0; + int bitPos = 0; + double numBytes = 0.0; + object structValue = Activator.CreateInstance(structType); + + + var infos = structValue.GetType() +#if NETSTANDARD1_3 + .GetTypeInfo().DeclaredFields; +#else + .GetFields(); +#endif + + foreach (var info in infos) + { + switch (info.FieldType.Name) + { + case "Boolean": + // get the value + bytePos = (int)Math.Floor(numBytes); + bitPos = (int)((numBytes - (double)bytePos) / 0.125); + if ((bytes[bytePos] & (int)Math.Pow(2, bitPos)) != 0) + info.SetValue(structValue, true); + else + info.SetValue(structValue, false); + numBytes += 0.125; + break; + case "Byte": + numBytes = Math.Ceiling(numBytes); + info.SetValue(structValue, (byte)(bytes[(int)numBytes])); + numBytes++; + break; + case "Int16": + numBytes = Math.Ceiling(numBytes); + if ((numBytes / 2 - Math.Floor(numBytes / 2.0)) > 0) + numBytes++; + // get the value + ushort source = Word.FromBytes(bytes[(int)numBytes + 1], bytes[(int)numBytes]); + info.SetValue(structValue, source.ConvertToShort()); + numBytes += 2; + break; + case "UInt16": + numBytes = Math.Ceiling(numBytes); + if ((numBytes / 2 - Math.Floor(numBytes / 2.0)) > 0) + numBytes++; + // get the value + info.SetValue(structValue, Word.FromBytes(bytes[(int)numBytes + 1], + bytes[(int)numBytes])); + numBytes += 2; + break; + case "Int32": + numBytes = Math.Ceiling(numBytes); + if ((numBytes / 2 - Math.Floor(numBytes / 2.0)) > 0) + numBytes++; + // get the value + uint sourceUInt = DWord.FromBytes(bytes[(int)numBytes + 3], + bytes[(int)numBytes + 2], + bytes[(int)numBytes + 1], + bytes[(int)numBytes + 0]); + info.SetValue(structValue, sourceUInt.ConvertToInt()); + numBytes += 4; + break; + case "UInt32": + numBytes = Math.Ceiling(numBytes); + if ((numBytes / 2 - Math.Floor(numBytes / 2.0)) > 0) + numBytes++; + // get the value + info.SetValue(structValue, DWord.FromBytes(bytes[(int)numBytes], + bytes[(int)numBytes + 1], + bytes[(int)numBytes + 2], + bytes[(int)numBytes + 3])); + numBytes += 4; + break; + case "Single": + numBytes = Math.Ceiling(numBytes); + if ((numBytes / 2 - Math.Floor(numBytes / 2.0)) > 0) + numBytes++; + // get the value + info.SetValue(structValue, Real.FromByteArray(new byte[] { bytes[(int)numBytes], + bytes[(int)numBytes + 1], + bytes[(int)numBytes + 2], + bytes[(int)numBytes + 3] })); + numBytes += 4; + break; + case "Double": + numBytes = Math.Ceiling(numBytes); + if ((numBytes / 2 - Math.Floor(numBytes / 2.0)) > 0) + numBytes++; + // get the value + var data = new byte[8]; + Array.Copy(bytes, (int)numBytes, data, 0, 8); + info.SetValue(structValue, LReal.FromByteArray(data)); + numBytes += 8; + break; + case "String": + S7StringAttribute? attribute = info.GetCustomAttributes().SingleOrDefault(); + if (attribute == default(S7StringAttribute)) + throw new ArgumentException("Please add S7StringAttribute to the string field"); + + numBytes = Math.Ceiling(numBytes); + if ((numBytes / 2 - Math.Floor(numBytes / 2.0)) > 0) + numBytes++; + + // get the value + var sData = new byte[attribute.ReservedLengthInBytes]; + Array.Copy(bytes, (int)numBytes, sData, 0, sData.Length); + switch (attribute.Type) + { + case S7StringType.S7String: + info.SetValue(structValue, S7String.FromByteArray(sData)); + break; + case S7StringType.S7WString: + info.SetValue(structValue, S7WString.FromByteArray(sData)); + break; + default: + throw new ArgumentException("Please use a valid string type for the S7StringAttribute"); + } + + numBytes += sData.Length; + break; + default: + var buffer = new byte[GetStructSize(info.FieldType)]; + if (buffer.Length == 0) + continue; + Buffer.BlockCopy(bytes, (int)Math.Ceiling(numBytes), buffer, 0, buffer.Length); + info.SetValue(structValue, FromBytes(info.FieldType, buffer)); + numBytes += buffer.Length; + break; + } + } + return structValue; + } + + /// + /// Creates a byte array depending on the struct type. + /// + /// The struct object + /// A byte array or null if fails. + public static byte[] ToBytes(object structValue) + { + Type type = structValue.GetType(); + + int size = Struct.GetStructSize(type); + byte[] bytes = new byte[size]; + byte[]? bytes2 = null; + + int bytePos = 0; + int bitPos = 0; + double numBytes = 0.0; + + var infos = type +#if NETSTANDARD1_3 + .GetTypeInfo().DeclaredFields; +#else + .GetFields(); +#endif + + foreach (var info in infos) + { + bytes2 = null; + switch (info.FieldType.Name) + { + case "Boolean": + // get the value + bytePos = (int)Math.Floor(numBytes); + bitPos = (int)((numBytes - (double)bytePos) / 0.125); + if ((bool)info.GetValue(structValue)) + bytes[bytePos] |= (byte)Math.Pow(2, bitPos); // is true + else + bytes[bytePos] &= (byte)(~(byte)Math.Pow(2, bitPos)); // is false + numBytes += 0.125; + break; + case "Byte": + numBytes = (int)Math.Ceiling(numBytes); + bytePos = (int)numBytes; + bytes[bytePos] = (byte)info.GetValue(structValue); + numBytes++; + break; + case "Int16": + bytes2 = Int.ToByteArray((Int16)info.GetValue(structValue)); + break; + case "UInt16": + bytes2 = Word.ToByteArray((UInt16)info.GetValue(structValue)); + break; + case "Int32": + bytes2 = DInt.ToByteArray((Int32)info.GetValue(structValue)); + break; + case "UInt32": + bytes2 = DWord.ToByteArray((UInt32)info.GetValue(structValue)); + break; + case "Single": + bytes2 = Real.ToByteArray((float)info.GetValue(structValue)); + break; + case "Double": + bytes2 = LReal.ToByteArray((double)info.GetValue(structValue)); + break; + case "String": + S7StringAttribute? attribute = info.GetCustomAttributes().SingleOrDefault(); + if (attribute == default(S7StringAttribute)) + throw new ArgumentException("Please add S7StringAttribute to the string field"); + + bytes2 = attribute.Type switch + { + S7StringType.S7String => S7String.ToByteArray((string)info.GetValue(structValue), attribute.ReservedLength), + S7StringType.S7WString => S7WString.ToByteArray((string)info.GetValue(structValue), attribute.ReservedLength), + _ => throw new ArgumentException("Please use a valid string type for the S7StringAttribute") + }; + break; + } + if (bytes2 != null) + { + // add them + numBytes = Math.Ceiling(numBytes); + if ((numBytes / 2 - Math.Floor(numBytes / 2.0)) > 0) + numBytes++; + bytePos = (int)numBytes; + for (int bCnt = 0; bCnt < bytes2.Length; bCnt++) + bytes[bytePos + bCnt] = bytes2[bCnt]; + numBytes += bytes2.Length; + } + } + return bytes; + } + } +} diff --git a/src/Khd.Core.Plc/S7/Types/Timer.cs b/src/Khd.Core.Plc/S7/Types/Timer.cs new file mode 100644 index 0000000..b011b1d --- /dev/null +++ b/src/Khd.Core.Plc/S7/Types/Timer.cs @@ -0,0 +1,80 @@ +namespace Khd.Core.Plc.S7.Types +{ + /// + /// Converts the Timer data type to C# data type + /// + public static class Timer + { + /// + /// Converts the timer bytes to a double + /// + public static double FromByteArray(byte[] bytes) + { + double wert = 0; + + wert = ((bytes[0]) & 0x0F) * 100.0; + wert += ((bytes[1] >> 4) & 0x0F) * 10.0; + wert += ((bytes[1]) & 0x0F) * 1.0; + + // this value is not used... may for a nother exponation + //int unknown = (bytes[0] >> 6) & 0x03; + + switch ((bytes[0] >> 4) & 0x03) + { + case 0: + wert *= 0.01; + break; + case 1: + wert *= 0.1; + break; + case 2: + wert *= 1.0; + break; + case 3: + wert *= 10.0; + break; + } + + return wert; + } + + /// + /// Converts a ushort (UInt16) to an array of bytes formatted as time + /// + public static byte[] ToByteArray(UInt16 value) + { + byte[] bytes = new byte[2]; + bytes[1] = (byte)((int)value & 0xFF); + bytes[0] = (byte)((int)value >> 8 & 0xFF); + + return bytes; + } + + /// + /// Converts an array of ushorts (Uint16) to an array of bytes formatted as time + /// + public static byte[] ToByteArray(UInt16[] value) + { + ByteArray arr = new ByteArray(); + foreach (UInt16 val in value) + arr.Add(ToByteArray(val)); + return arr.Array; + } + + /// + /// Converts an array of bytes formatted as time to an array of doubles + /// + /// + /// + public static double[] ToArray(byte[] bytes) + { + double[] values = new double[bytes.Length / 2]; + + int counter = 0; + for (int cnt = 0; cnt < bytes.Length / 2; cnt++) + values[cnt] = FromByteArray(new byte[] { bytes[counter++], bytes[counter++] }); + + return values; + } + } +} diff --git a/src/Khd.Core.Plc/S7/Types/TypeHelper.cs b/src/Khd.Core.Plc/S7/Types/TypeHelper.cs new file mode 100644 index 0000000..53dc124 --- /dev/null +++ b/src/Khd.Core.Plc/S7/Types/TypeHelper.cs @@ -0,0 +1,41 @@ +using System.Runtime.InteropServices; + +namespace Khd.Core.Plc.S7.Types +{ + internal static class TypeHelper + { + /// + /// Converts an array of T to an array of bytes + /// + public static byte[] ToByteArray(T[] value, Func converter) where T : struct + { + var buffer = new byte[Marshal.SizeOf(default(T)) * value.Length]; + var stream = new MemoryStream(buffer); + foreach (var val in value) + { + stream.Write(converter(val), 0, 4); + } + + return buffer; + } + + /// + /// Converts an array of T repesented as S7 binary data to an array of T + /// + public static T[] ToArray(byte[] bytes, Func converter) where T : struct + { + var typeSize = Marshal.SizeOf(default(T)); + var entries = bytes.Length / typeSize; + var values = new T[entries]; + + for (int i = 0; i < entries; ++i) + { + var buffer = new byte[typeSize]; + Array.Copy(bytes, i * typeSize, buffer, 0, typeSize); + values[i] = converter(buffer); + } + + return values; + } + } +} diff --git a/src/Khd.Core.Plc/S7/Types/Word.cs b/src/Khd.Core.Plc/S7/Types/Word.cs new file mode 100644 index 0000000..d8d78b8 --- /dev/null +++ b/src/Khd.Core.Plc/S7/Types/Word.cs @@ -0,0 +1,69 @@ +namespace Khd.Core.Plc.S7.Types +{ + /// + /// Contains the conversion methods to convert Words from S7 plc to C#. + /// + public static class Word + { + /// + /// Converts a word (2 bytes) to ushort (UInt16) + /// + public static UInt16 FromByteArray(byte[] bytes) + { + if (bytes.Length != 2) + { + throw new ArgumentException("Wrong number of bytes. Bytes array must contain 2 bytes."); + } + + return (UInt16)((bytes[0] << 8) | bytes[1]); + } + + + /// + /// Converts 2 bytes to ushort (UInt16) + /// + public static UInt16 FromBytes(byte b1, byte b2) + { + return (UInt16)((b2 << 8) | b1); + } + + + /// + /// Converts a ushort (UInt16) to word (2 bytes) + /// + public static byte[] ToByteArray(UInt16 value) + { + byte[] bytes = new byte[2]; + + bytes[1] = (byte)(value & 0xFF); + bytes[0] = (byte)((value >> 8) & 0xFF); + + return bytes; + } + + /// + /// Converts an array of ushort (UInt16) to an array of bytes + /// + public static byte[] ToByteArray(UInt16[] value) + { + ByteArray arr = new ByteArray(); + foreach (UInt16 val in value) + arr.Add(ToByteArray(val)); + return arr.Array; + } + + /// + /// Converts an array of bytes to an array of ushort + /// + public static UInt16[] ToArray(byte[] bytes) + { + UInt16[] values = new UInt16[bytes.Length / 2]; + + int counter = 0; + for (int cnt = 0; cnt < bytes.Length / 2; cnt++) + values[cnt] = FromByteArray(new byte[] { bytes[counter++], bytes[counter++] }); + + return values; + } + } +} diff --git a/src/Khd.Core.Plc/StaticPlcHelper.cs b/src/Khd.Core.Plc/StaticPlcHelper.cs new file mode 100644 index 0000000..07ff01b --- /dev/null +++ b/src/Khd.Core.Plc/StaticPlcHelper.cs @@ -0,0 +1,130 @@ +using System.Text; + +namespace Khd.Core.Plc +{ + /// + /// Plc帮助类 + /// + public static class StaticPlcHelper + { + /// + /// 进行高低位转换后,写入Plc地址 + /// + /// plc + /// 写入地址 + /// 值 + /// 长度 + public static void WriteToPoint(this Plc.S7.Plc plc, string address, object? valueString, string? len) + { + if (len == null) + { + throw new ArgumentException("StaticPlcHelper Ex len is null"); + } + if (valueString == null) + { + throw new ArgumentException("StaticPlcHelper Ex valueString is null"); + } + plc.Write(address, GetValue(len, valueString)); + } + + /// + /// 写入RFID + /// + /// plc + /// 读取地址 + /// 长度 + /// 读取到的RFID + public static void WriteRFID(this Plc.S7.Plc plc, string address, string value,int len = 15) + { + string[] adds = address.Split("."); + int db = int.Parse(adds[0].Replace("DB", "")); + int startByteAdr = int.Parse(adds[1].Replace("DBX", "")); + + // 将 value 转换为字节数组,确保其长度符合要求 + byte[] byteArray = Encoding.ASCII.GetBytes(value); + if (byteArray.Length > len) + { + throw new ArgumentException($"Value length exceeds the specified length of {len} bytes."); + } + + // 填充字节数组到指定长度 + byte[] dataToWrite = new byte[len]; + Array.Copy(byteArray, dataToWrite, byteArray.Length); + + plc.Write(S7.DataType.DataBlock, db, startByteAdr, dataToWrite); + + } + + + + /// + /// 读取RFID + /// + /// plc + /// 读取地址 + /// 长度 + /// 读取到的RFID + public static string? ReadRFID(this Plc.S7.Plc plc, string address, int len = 36) + { + string[] adds = address.Split("."); + int db = int.Parse(adds[0].Replace("DB", "")); + int startByteAdr = int.Parse(adds[1].Replace("DBX", "")); + var result = (byte[]?)plc.Read(S7.DataType.DataBlock, db, startByteAdr, S7.VarType.Byte, len); + if (result == null) + { + return null; + } + string res = Encoding.UTF8.GetString(result).Replace("\0", "").Replace("$", "").Replace("\\u", "").Trim(); + + if (res.Contains("JYHB")) + { + return res[res.IndexOf('J')..].Substring(0, 12); + } + else if (res.Contains('C')) + { + return res[res.IndexOf('C')..]; + } + else + { + return ""; + } + } + + + /// + /// 电气写入点位高低位转换 + /// + /// 点位地址位长度 + /// 写入数值 + /// + public static object GetValue(string? len, object value) + { + + if (len == "2") + { + return Convert.ToInt16(value); + } + if (len == "4") + { + return Convert.ToInt32(value); + } + if (len == "6") + { + return Convert.ToByte(value); + } + if (len == "8") + { + return Convert.ToString(value); + } + if (len == "10") + { + return Convert.ToBoolean(value); + } + if (len == "12") + { + return Convert.ToSingle(value); + } + throw new ArgumentException("StaticPlcHelper Ex len is not support"); + } + } +} diff --git a/src/Khd.Core.Thrift.Client/Khd.Core.Thrift.Client.csproj b/src/Khd.Core.Thrift.Client/Khd.Core.Thrift.Client.csproj new file mode 100644 index 0000000..2a45cf1 --- /dev/null +++ b/src/Khd.Core.Thrift.Client/Khd.Core.Thrift.Client.csproj @@ -0,0 +1,18 @@ + + + + Exe + net6.0 + enable + enable + + + + + + + + + + + diff --git a/src/Khd.Core.Thrift.Client/Program.cs b/src/Khd.Core.Thrift.Client/Program.cs new file mode 100644 index 0000000..5255ef1 --- /dev/null +++ b/src/Khd.Core.Thrift.Client/Program.cs @@ -0,0 +1,29 @@ +using Thrift.Protocol; +using Thrift.Transport; + +internal class Program +{ + private static void Main(string[] args) + { + Console.WriteLine("Hello, Client!"); + SendTest("List1"); + } + public static void SendTest(string Message) + { + try + { + TTransport transport = new TSocket("localhost", 9091); + transport.Open(); + TProtocol protocol = new TBinaryProtocol(transport); + WcsThrift.Client client = new WcsThrift.Client(protocol); + //Console.WriteLine(client.hello("Sunzy")); + Console.WriteLine(client.SendCar(new List() { Message }, "P1001", "10")); + Console.ReadLine(); + } + catch (Exception ex) + { + // 处理异常 + Console.WriteLine($"Error: {ex.Message}"); + } + } +} \ No newline at end of file diff --git a/src/Khd.Core.Thrift.Client/Properties/launchSettings.json b/src/Khd.Core.Thrift.Client/Properties/launchSettings.json new file mode 100644 index 0000000..33504c9 --- /dev/null +++ b/src/Khd.Core.Thrift.Client/Properties/launchSettings.json @@ -0,0 +1,8 @@ +{ + "profiles": { + "WSL": { + "commandName": "WSL2", + "distributionName": "" + } + } +} \ No newline at end of file diff --git a/src/Khd.Core.Thrift.Server/Khd.Core.Thrift.Server.csproj b/src/Khd.Core.Thrift.Server/Khd.Core.Thrift.Server.csproj new file mode 100644 index 0000000..2a45cf1 --- /dev/null +++ b/src/Khd.Core.Thrift.Server/Khd.Core.Thrift.Server.csproj @@ -0,0 +1,18 @@ + + + + Exe + net6.0 + enable + enable + + + + + + + + + + + diff --git a/src/Khd.Core.Thrift.Server/Program.cs b/src/Khd.Core.Thrift.Server/Program.cs new file mode 100644 index 0000000..ec28df1 --- /dev/null +++ b/src/Khd.Core.Thrift.Server/Program.cs @@ -0,0 +1,27 @@ +using Thrift.Server; +using Thrift.Transport; +using ThriftService; + +internal class Program +{ + private static void Main(string[] args) + { + while (true) + { + try + { + WcsServer wcsServer = new WcsServer(); + WcsThrift.Processor processor = new WcsThrift.Processor(wcsServer); + TServerTransport serverTransport = new TServerSocket(9091); + TServer server = new TSimpleServer(processor, serverTransport); + Console.WriteLine("Starting the server..."); + server.Serve(); + } + catch (Exception ex) + { + Console.WriteLine(ex.StackTrace); + } + Console.WriteLine("done."); + } + } +} \ No newline at end of file diff --git a/src/Khd.Core.Thrift.Server/WcsServer.cs b/src/Khd.Core.Thrift.Server/WcsServer.cs new file mode 100644 index 0000000..c952a76 --- /dev/null +++ b/src/Khd.Core.Thrift.Server/WcsServer.cs @@ -0,0 +1,17 @@ +namespace ThriftService +{ + public class WcsServer : WcsThrift.Iface + { + public string hello(string name) + { + Console.WriteLine($"hello {name}"); + return $"ServerResponse receive from client name:{name}"; + } + public string SendCar(List carlist, string order_code, string amount) + { + Console.WriteLine($"hello carlist[0]:{carlist.FirstOrDefault()}|order_code:{order_code}|amount:{amount}"); + return $"ServerResponse receive from client order_code:{order_code}"; + } + + } +} diff --git a/src/Khd.Core.Thrift/Khd.Core.Thrift.csproj b/src/Khd.Core.Thrift/Khd.Core.Thrift.csproj new file mode 100644 index 0000000..458cf77 --- /dev/null +++ b/src/Khd.Core.Thrift/Khd.Core.Thrift.csproj @@ -0,0 +1,14 @@ + + + + net6.0 + enable + enable + + + + + + + + diff --git a/src/Khd.Core.Thrift/WcsThrift.cs b/src/Khd.Core.Thrift/WcsThrift.cs new file mode 100644 index 0000000..3c91d33 --- /dev/null +++ b/src/Khd.Core.Thrift/WcsThrift.cs @@ -0,0 +1,862 @@ +/** + * Autogenerated by Thrift Compiler (0.9.3) + * + * DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING + * @generated + */ +using System.Text; +using Thrift; +using Thrift.Protocol; + +public partial class WcsThrift +{ + public interface Iface + { + string hello(string name); +#if SILVERLIGHT + IAsyncResult Begin_hello(AsyncCallback callback, object state, string name); + string End_hello(IAsyncResult asyncResult); +#endif + string SendCar(List carlist, string order_code, string amount); +#if SILVERLIGHT + IAsyncResult Begin_SendCar(AsyncCallback callback, object state, List carlist, string order_code, string amount); + string End_SendCar(IAsyncResult asyncResult); +#endif + } + + public class Client : IDisposable, Iface + { + public Client(TProtocol prot) : this(prot, prot) + { + } + + public Client(TProtocol iprot, TProtocol oprot) + { + iprot_ = iprot; + oprot_ = oprot; + } + + protected TProtocol iprot_; + protected TProtocol oprot_; + protected int seqid_; + + public TProtocol InputProtocol + { + get { return iprot_; } + } + public TProtocol OutputProtocol + { + get { return oprot_; } + } + + + #region " IDisposable Support " + private bool _IsDisposed; + + // IDisposable + public void Dispose() + { + Dispose(true); + } + + + protected virtual void Dispose(bool disposing) + { + if (!_IsDisposed) + { + if (disposing) + { + if (iprot_ != null) + { + ((IDisposable)iprot_).Dispose(); + } + if (oprot_ != null) + { + ((IDisposable)oprot_).Dispose(); + } + } + } + _IsDisposed = true; + } + #endregion + + + +#if SILVERLIGHT + public IAsyncResult Begin_hello(AsyncCallback callback, object state, string name) + { + return send_hello(callback, state, name); + } + + public string End_hello(IAsyncResult asyncResult) + { + oprot_.Transport.EndFlush(asyncResult); + return recv_hello(); + } + +#endif + + public string hello(string name) + { +#if !SILVERLIGHT + send_hello(name); + return recv_hello(); + +#else + var asyncResult = Begin_hello(null, null, name); + return End_hello(asyncResult); + +#endif + } +#if SILVERLIGHT + public IAsyncResult send_hello(AsyncCallback callback, object state, string name) +#else + public void send_hello(string name) +#endif + { + oprot_.WriteMessageBegin(new TMessage("hello", TMessageType.Call, seqid_)); + hello_args args = new hello_args(); + args.Name = name; + args.Write(oprot_); + oprot_.WriteMessageEnd(); +#if SILVERLIGHT + return oprot_.Transport.BeginFlush(callback, state); +#else + oprot_.Transport.Flush(); +#endif + } + + public string recv_hello() + { + TMessage msg = iprot_.ReadMessageBegin(); + if (msg.Type == TMessageType.Exception) + { + TApplicationException x = TApplicationException.Read(iprot_); + iprot_.ReadMessageEnd(); + throw x; + } + hello_result result = new hello_result(); + result.Read(iprot_); + iprot_.ReadMessageEnd(); + if (result.__isset.success) + { + return result.Success; + } + throw new TApplicationException(TApplicationException.ExceptionType.MissingResult, "hello failed: unknown result"); + } + + +#if SILVERLIGHT + public IAsyncResult Begin_SendCar(AsyncCallback callback, object state, List carlist, string order_code, string amount) + { + return send_SendCar(callback, state, carlist, order_code, amount); + } + + public string End_SendCar(IAsyncResult asyncResult) + { + oprot_.Transport.EndFlush(asyncResult); + return recv_SendCar(); + } + +#endif + + public string SendCar(List carlist, string order_code, string amount) + { +#if !SILVERLIGHT + send_SendCar(carlist, order_code, amount); + return recv_SendCar(); + +#else + var asyncResult = Begin_SendCar(null, null, carlist, order_code, amount); + return End_SendCar(asyncResult); + +#endif + } +#if SILVERLIGHT + public IAsyncResult send_SendCar(AsyncCallback callback, object state, List carlist, string order_code, string amount) +#else + public void send_SendCar(List carlist, string order_code, string amount) +#endif + { + oprot_.WriteMessageBegin(new TMessage("SendCar", TMessageType.Call, seqid_)); + SendCar_args args = new SendCar_args(); + args.Carlist = carlist; + args.Order_code = order_code; + args.Amount = amount; + args.Write(oprot_); + oprot_.WriteMessageEnd(); +#if SILVERLIGHT + return oprot_.Transport.BeginFlush(callback, state); +#else + oprot_.Transport.Flush(); +#endif + } + + public string recv_SendCar() + { + TMessage msg = iprot_.ReadMessageBegin(); + if (msg.Type == TMessageType.Exception) + { + TApplicationException x = TApplicationException.Read(iprot_); + iprot_.ReadMessageEnd(); + throw x; + } + SendCar_result result = new SendCar_result(); + result.Read(iprot_); + iprot_.ReadMessageEnd(); + if (result.__isset.success) + { + return result.Success; + } + throw new TApplicationException(TApplicationException.ExceptionType.MissingResult, "SendCar failed: unknown result"); + } + + } + public class Processor : TProcessor + { + public Processor(Iface iface) + { + iface_ = iface; + processMap_["hello"] = hello_Process; + processMap_["SendCar"] = SendCar_Process; + } + + protected delegate void ProcessFunction(int seqid, TProtocol iprot, TProtocol oprot); + private Iface iface_; + protected Dictionary processMap_ = new Dictionary(); + + public bool Process(TProtocol iprot, TProtocol oprot) + { + try + { + TMessage msg = iprot.ReadMessageBegin(); + ProcessFunction fn; + processMap_.TryGetValue(msg.Name, out fn); + if (fn == null) + { + TProtocolUtil.Skip(iprot, TType.Struct); + iprot.ReadMessageEnd(); + TApplicationException x = new TApplicationException(TApplicationException.ExceptionType.UnknownMethod, "Invalid method name: '" + msg.Name + "'"); + oprot.WriteMessageBegin(new TMessage(msg.Name, TMessageType.Exception, msg.SeqID)); + x.Write(oprot); + oprot.WriteMessageEnd(); + oprot.Transport.Flush(); + return true; + } + fn(msg.SeqID, iprot, oprot); + } + catch (IOException) + { + return false; + } + return true; + } + + public void hello_Process(int seqid, TProtocol iprot, TProtocol oprot) + { + hello_args args = new hello_args(); + args.Read(iprot); + iprot.ReadMessageEnd(); + hello_result result = new hello_result(); + result.Success = iface_.hello(args.Name); + oprot.WriteMessageBegin(new TMessage("hello", TMessageType.Reply, seqid)); + result.Write(oprot); + oprot.WriteMessageEnd(); + oprot.Transport.Flush(); + } + + public void SendCar_Process(int seqid, TProtocol iprot, TProtocol oprot) + { + SendCar_args args = new SendCar_args(); + args.Read(iprot); + iprot.ReadMessageEnd(); + SendCar_result result = new SendCar_result(); + result.Success = iface_.SendCar(args.Carlist, args.Order_code, args.Amount); + oprot.WriteMessageBegin(new TMessage("SendCar", TMessageType.Reply, seqid)); + result.Write(oprot); + oprot.WriteMessageEnd(); + oprot.Transport.Flush(); + } + + } + + +#if !SILVERLIGHT + [Serializable] +#endif + public partial class hello_args : TBase + { + private string _name; + + public string Name + { + get + { + return _name; + } + set + { + __isset.name = true; + this._name = value; + } + } + + + public Isset __isset; +#if !SILVERLIGHT + [Serializable] +#endif + public struct Isset + { + public bool name; + } + + public hello_args() + { + } + + public void Read(TProtocol iprot) + { + iprot.IncrementRecursionDepth(); + try + { + TField field; + iprot.ReadStructBegin(); + while (true) + { + field = iprot.ReadFieldBegin(); + if (field.Type == TType.Stop) + { + break; + } + switch (field.ID) + { + case 1: + if (field.Type == TType.String) + { + Name = iprot.ReadString(); + } + else + { + TProtocolUtil.Skip(iprot, field.Type); + } + break; + default: + TProtocolUtil.Skip(iprot, field.Type); + break; + } + iprot.ReadFieldEnd(); + } + iprot.ReadStructEnd(); + } + finally + { + iprot.DecrementRecursionDepth(); + } + } + + public void Write(TProtocol oprot) + { + oprot.IncrementRecursionDepth(); + try + { + TStruct struc = new TStruct("hello_args"); + oprot.WriteStructBegin(struc); + TField field = new TField(); + if (Name != null && __isset.name) + { + field.Name = "name"; + field.Type = TType.String; + field.ID = 1; + oprot.WriteFieldBegin(field); + oprot.WriteString(Name); + oprot.WriteFieldEnd(); + } + oprot.WriteFieldStop(); + oprot.WriteStructEnd(); + } + finally + { + oprot.DecrementRecursionDepth(); + } + } + + public override string ToString() + { + StringBuilder __sb = new StringBuilder("hello_args("); + bool __first = true; + if (Name != null && __isset.name) + { + if (!__first) { __sb.Append(", "); } + __first = false; + __sb.Append("Name: "); + __sb.Append(Name); + } + __sb.Append(")"); + return __sb.ToString(); + } + + } + + +#if !SILVERLIGHT + [Serializable] +#endif + public partial class hello_result : TBase + { + private string _success; + + public string Success + { + get + { + return _success; + } + set + { + __isset.success = true; + this._success = value; + } + } + + + public Isset __isset; +#if !SILVERLIGHT + [Serializable] +#endif + public struct Isset + { + public bool success; + } + + public hello_result() + { + } + + public void Read(TProtocol iprot) + { + iprot.IncrementRecursionDepth(); + try + { + TField field; + iprot.ReadStructBegin(); + while (true) + { + field = iprot.ReadFieldBegin(); + if (field.Type == TType.Stop) + { + break; + } + switch (field.ID) + { + case 0: + if (field.Type == TType.String) + { + Success = iprot.ReadString(); + } + else + { + TProtocolUtil.Skip(iprot, field.Type); + } + break; + default: + TProtocolUtil.Skip(iprot, field.Type); + break; + } + iprot.ReadFieldEnd(); + } + iprot.ReadStructEnd(); + } + finally + { + iprot.DecrementRecursionDepth(); + } + } + + public void Write(TProtocol oprot) + { + oprot.IncrementRecursionDepth(); + try + { + TStruct struc = new TStruct("hello_result"); + oprot.WriteStructBegin(struc); + TField field = new TField(); + + if (this.__isset.success) + { + if (Success != null) + { + field.Name = "Success"; + field.Type = TType.String; + field.ID = 0; + oprot.WriteFieldBegin(field); + oprot.WriteString(Success); + oprot.WriteFieldEnd(); + } + } + oprot.WriteFieldStop(); + oprot.WriteStructEnd(); + } + finally + { + oprot.DecrementRecursionDepth(); + } + } + + public override string ToString() + { + StringBuilder __sb = new StringBuilder("hello_result("); + bool __first = true; + if (Success != null && __isset.success) + { + if (!__first) { __sb.Append(", "); } + __first = false; + __sb.Append("Success: "); + __sb.Append(Success); + } + __sb.Append(")"); + return __sb.ToString(); + } + + } + + +#if !SILVERLIGHT + [Serializable] +#endif + public partial class SendCar_args : TBase + { + private List _carlist; + private string _order_code; + private string _amount; + + public List Carlist + { + get + { + return _carlist; + } + set + { + __isset.carlist = true; + this._carlist = value; + } + } + + public string Order_code + { + get + { + return _order_code; + } + set + { + __isset.order_code = true; + this._order_code = value; + } + } + + public string Amount + { + get + { + return _amount; + } + set + { + __isset.amount = true; + this._amount = value; + } + } + + + public Isset __isset; +#if !SILVERLIGHT + [Serializable] +#endif + public struct Isset + { + public bool carlist; + public bool order_code; + public bool amount; + } + + public SendCar_args() + { + } + + public void Read(TProtocol iprot) + { + iprot.IncrementRecursionDepth(); + try + { + TField field; + iprot.ReadStructBegin(); + while (true) + { + field = iprot.ReadFieldBegin(); + if (field.Type == TType.Stop) + { + break; + } + switch (field.ID) + { + case 1: + if (field.Type == TType.List) + { + { + Carlist = new List(); + TList _list0 = iprot.ReadListBegin(); + for (int _i1 = 0; _i1 < _list0.Count; ++_i1) + { + string _elem2; + _elem2 = iprot.ReadString(); + Carlist.Add(_elem2); + } + iprot.ReadListEnd(); + } + } + else + { + TProtocolUtil.Skip(iprot, field.Type); + } + break; + case 2: + if (field.Type == TType.String) + { + Order_code = iprot.ReadString(); + } + else + { + TProtocolUtil.Skip(iprot, field.Type); + } + break; + case 3: + if (field.Type == TType.String) + { + Amount = iprot.ReadString(); + } + else + { + TProtocolUtil.Skip(iprot, field.Type); + } + break; + default: + TProtocolUtil.Skip(iprot, field.Type); + break; + } + iprot.ReadFieldEnd(); + } + iprot.ReadStructEnd(); + } + finally + { + iprot.DecrementRecursionDepth(); + } + } + + public void Write(TProtocol oprot) + { + oprot.IncrementRecursionDepth(); + try + { + TStruct struc = new TStruct("SendCar_args"); + oprot.WriteStructBegin(struc); + TField field = new TField(); + if (Carlist != null && __isset.carlist) + { + field.Name = "carlist"; + field.Type = TType.List; + field.ID = 1; + oprot.WriteFieldBegin(field); + { + oprot.WriteListBegin(new TList(TType.String, Carlist.Count)); + foreach (string _iter3 in Carlist) + { + oprot.WriteString(_iter3); + } + oprot.WriteListEnd(); + } + oprot.WriteFieldEnd(); + } + if (Order_code != null && __isset.order_code) + { + field.Name = "order_code"; + field.Type = TType.String; + field.ID = 2; + oprot.WriteFieldBegin(field); + oprot.WriteString(Order_code); + oprot.WriteFieldEnd(); + } + if (Amount != null && __isset.amount) + { + field.Name = "amount"; + field.Type = TType.String; + field.ID = 3; + oprot.WriteFieldBegin(field); + oprot.WriteString(Amount); + oprot.WriteFieldEnd(); + } + oprot.WriteFieldStop(); + oprot.WriteStructEnd(); + } + finally + { + oprot.DecrementRecursionDepth(); + } + } + + public override string ToString() + { + StringBuilder __sb = new StringBuilder("SendCar_args("); + bool __first = true; + if (Carlist != null && __isset.carlist) + { + if (!__first) { __sb.Append(", "); } + __first = false; + __sb.Append("Carlist: "); + __sb.Append(Carlist); + } + if (Order_code != null && __isset.order_code) + { + if (!__first) { __sb.Append(", "); } + __first = false; + __sb.Append("Order_code: "); + __sb.Append(Order_code); + } + if (Amount != null && __isset.amount) + { + if (!__first) { __sb.Append(", "); } + __first = false; + __sb.Append("Amount: "); + __sb.Append(Amount); + } + __sb.Append(")"); + return __sb.ToString(); + } + + } + + +#if !SILVERLIGHT + [Serializable] +#endif + public partial class SendCar_result : TBase + { + private string _success; + + public string Success + { + get + { + return _success; + } + set + { + __isset.success = true; + this._success = value; + } + } + + + public Isset __isset; +#if !SILVERLIGHT + [Serializable] +#endif + public struct Isset + { + public bool success; + } + + public SendCar_result() + { + } + + public void Read(TProtocol iprot) + { + iprot.IncrementRecursionDepth(); + try + { + TField field; + iprot.ReadStructBegin(); + while (true) + { + field = iprot.ReadFieldBegin(); + if (field.Type == TType.Stop) + { + break; + } + switch (field.ID) + { + case 0: + if (field.Type == TType.String) + { + Success = iprot.ReadString(); + } + else + { + TProtocolUtil.Skip(iprot, field.Type); + } + break; + default: + TProtocolUtil.Skip(iprot, field.Type); + break; + } + iprot.ReadFieldEnd(); + } + iprot.ReadStructEnd(); + } + finally + { + iprot.DecrementRecursionDepth(); + } + } + + public void Write(TProtocol oprot) + { + oprot.IncrementRecursionDepth(); + try + { + TStruct struc = new TStruct("SendCar_result"); + oprot.WriteStructBegin(struc); + TField field = new TField(); + + if (this.__isset.success) + { + if (Success != null) + { + field.Name = "Success"; + field.Type = TType.String; + field.ID = 0; + oprot.WriteFieldBegin(field); + oprot.WriteString(Success); + oprot.WriteFieldEnd(); + } + } + oprot.WriteFieldStop(); + oprot.WriteStructEnd(); + } + finally + { + oprot.DecrementRecursionDepth(); + } + } + + public override string ToString() + { + StringBuilder __sb = new StringBuilder("SendCar_result("); + bool __first = true; + if (Success != null && __isset.success) + { + if (!__first) { __sb.Append(", "); } + __first = false; + __sb.Append("Success: "); + __sb.Append(Success); + } + __sb.Append(")"); + return __sb.ToString(); + } + + } + +} diff --git a/src/Khd.Core.Wcs/Global/CommFunction.cs b/src/Khd.Core.Wcs/Global/CommFunction.cs new file mode 100644 index 0000000..8dd9185 --- /dev/null +++ b/src/Khd.Core.Wcs/Global/CommFunction.cs @@ -0,0 +1,30 @@ +using Khd.Core.Wcs.Global; +//using KingerRobot.WMS.Dao; + +namespace Khd.Core.Wcs +{ + public class CommFunction + { + /// + /// 生成任务号 + /// + /// + public static string CreateSerialNo() + { + int SerialNo = 0; + var dic = StaticData.BaseDictionary.Where(t => t.dicKey == "WCS_SerialNo").FirstOrDefault(); + if (!dic.updateTime.GetValueOrDefault().ToString("yyyyMMdd").Equals(DateTime.Now.ToString("yyyyMMdd"))) + { + var ss = DateTime.Now.ToString("MMdd") + "00001"; + SerialNo = Convert.ToInt32(ss); + } + else + { + SerialNo = Convert.ToInt32(dic.dicValue) + 1; + } + dic.updateTime = DateTime.Now; + dic.dicValue = SerialNo.ToString(); + return SerialNo.ToString(); + } + } +} diff --git a/src/Khd.Core.Wcs/Global/HttpHelper.cs b/src/Khd.Core.Wcs/Global/HttpHelper.cs new file mode 100644 index 0000000..f74e8fe --- /dev/null +++ b/src/Khd.Core.Wcs/Global/HttpHelper.cs @@ -0,0 +1,166 @@ +using System.Text; + +namespace Khd.Core.Wcs +{ + public class HttpHelper + { + + public static string SendPostMessage(string ip, int port, string url, string message, string contentType = "application/Text") + { + string retsult = HttpPost("http://" + ip + ":" + port + "/" + url, message, contentType, 30, null); + return retsult; + } + + + public static string SendGetMessage(string ip, int port, string url) + { + string retsult = HttpGet("http://" + ip + ":" + port + "/" + url); + return retsult; + } + + /// + /// 发起POST同步请求 + /// + /// + /// + /// + /// application/xml、application/json、application/text、application/x-www-form-urlencoded + /// 填充消息头 + /// + public static string HttpPost(string url, string postData = null, string contentType = null, int timeOut = 30, Dictionary headers = null) + { + postData = postData ?? ""; + using (HttpClient client = new HttpClient()) + { + if (headers != null) + { + foreach (var header in headers) + client.DefaultRequestHeaders.Add(header.Key, header.Value); + } + using (HttpContent httpContent = new StringContent(postData, Encoding.UTF8)) + { + if (contentType != null) + httpContent.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue(contentType); + + HttpResponseMessage response = client.PostAsync(url, httpContent).Result; + return response.Content.ReadAsStringAsync().Result; + } + } + } + + + /// + /// 发起POST异步请求 + /// + /// + /// + /// application/xml、application/json、application/text、application/x-www-form-urlencoded + /// 填充消息头 + /// + public static async Task HttpPostAsync(string url, string postData = null, string contentType = null, int timeOut = 30, Dictionary headers = null) + { + postData = postData ?? ""; + using (HttpClient client = new HttpClient()) + { + client.Timeout = new TimeSpan(0, 0, timeOut); + if (headers != null) + { + foreach (var header in headers) + client.DefaultRequestHeaders.Add(header.Key, header.Value); + } + using (HttpContent httpContent = new StringContent(postData, Encoding.UTF8)) + { + if (contentType != null) + httpContent.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue(contentType); + + HttpResponseMessage response = await client.PostAsync(url, httpContent); + return await response.Content.ReadAsStringAsync(); + } + } + } + + /// + /// 发起GET同步请求 + /// + /// + /// + /// + /// + public static string HttpGet(string url, Dictionary headers = null) + { + using (HttpClient client = new HttpClient()) + { + if (headers != null) + { + foreach (var header in headers) + client.DefaultRequestHeaders.Add(header.Key, header.Value); + } + HttpResponseMessage response = client.GetAsync(url).Result; + return response.Content.ReadAsStringAsync().Result; + } + } + + /// + /// 发起GET异步请求 + /// + /// + /// + /// + /// + public static async Task HttpGetAsync(string url, Dictionary headers = null) + { + using (HttpClient client = new HttpClient()) + { + if (headers != null) + { + foreach (var header in headers) + client.DefaultRequestHeaders.Add(header.Key, header.Value); + } + HttpResponseMessage response = await client.GetAsync(url); + return await response.Content.ReadAsStringAsync(); + } + } + + /// + /// 发起GET同步请求 + /// + /// + /// + /// + /// + public static string HttpDelete(string url, Dictionary headers = null) + { + using (HttpClient client = new HttpClient()) + { + if (headers != null) + { + foreach (var header in headers) + client.DefaultRequestHeaders.Add(header.Key, header.Value); + } + HttpResponseMessage response = client.DeleteAsync(url).Result; + return response.Content.ReadAsStringAsync().Result; + } + } + + /// + /// 发起GET异步请求 + /// + /// + /// + /// + /// + public static async Task HttpDeleteAsync(string url, Dictionary headers = null) + { + using (HttpClient client = new HttpClient()) + { + if (headers != null) + { + foreach (var header in headers) + client.DefaultRequestHeaders.Add(header.Key, header.Value); + } + HttpResponseMessage response = await client.DeleteAsync(url); + return await response.Content.ReadAsStringAsync(); + } + } + } +} diff --git a/src/Khd.Core.Wcs/Global/PlcConfig.cs b/src/Khd.Core.Wcs/Global/PlcConfig.cs new file mode 100644 index 0000000..3873161 --- /dev/null +++ b/src/Khd.Core.Wcs/Global/PlcConfig.cs @@ -0,0 +1,23 @@ +using Khd.Core.Plc.S7; + +namespace Khd.Core.Wcs.Global +{ + public class PlcConfig + { + public CpuType CpuType { get; set; } + public string IP { get; set; } + public int Port { get; set; } + public short Rack { get; set; } + public short Slot { get; set; } + public int Code { get; set; } + } + public static class ConnectionStrings + { + public static string? ConnectionString { get; set; } + } + public class CommonLock + { + public static object tableLock = new object(); + public static object Xlock = new object(); + } +} diff --git a/src/Khd.Core.Wcs/Global/SnowflakeIdGenerator.cs b/src/Khd.Core.Wcs/Global/SnowflakeIdGenerator.cs new file mode 100644 index 0000000..7fe3b67 --- /dev/null +++ b/src/Khd.Core.Wcs/Global/SnowflakeIdGenerator.cs @@ -0,0 +1,62 @@ +namespace Khd.Core.Wcs.Wcs +{ + public class SnowflakeIdGenerator + { + private long _lastTimestamp = 0; // 上一次生成的时间戳 + private readonly int _dataCenterId; // 数据中心ID + private readonly int _workerId; // 工作节点ID + private long _sequence = 0; // 自增序列号 + + public SnowflakeIdGenerator(int dataCenterId, int workerId) + { + if (dataCenterId < 0 || dataCenterId > 31) + throw new ArgumentException("Data center ID must be between 0 and 31."); + if (workerId < 0 || workerId > 31) + throw new ArgumentException("Worker ID must be between 0 and 31."); + + _dataCenterId = dataCenterId; // 初始化数据中心ID + _workerId = workerId; // 初始化工作节点ID + } + + public long GenerateId() + { + long timestamp = GetTimestamp(); // 获取当前时间戳 + + if (timestamp < _lastTimestamp) // 如果当前时间戳小于上一次生成的时间戳 + throw new Exception("Clock moved backwards. Refusing to generate ID."); + + if (timestamp == _lastTimestamp) // 如果当前时间戳与上一次生成的时间戳相同 + { + _sequence = (_sequence + 1) & 4095; // 自增序列号,并将其限制在0~4095之间 + if (_sequence == 0) + timestamp = WaitNextMillis(_lastTimestamp); // 如果自增序列号达到上限,等待下一毫秒的时间戳 + } + else + { + _sequence = 0; // 如果当前时间戳发生变化,重置自增序列号 + } + + _lastTimestamp = timestamp; // 更新上一次生成的时间戳 + + // 生成雪花Id,通过位运算将各个部分组合起来 + return ((timestamp - 1580000000000L) << 22) // 时间戳部分(中间的 - 1580000000000L 是为了减少占用位数) + | (_dataCenterId << 17) // 数据中心ID部分 + | (_workerId << 12) // 工作节点ID部分 + | _sequence; // 自增序列号部分 + } + + private long GetTimestamp() + { + return DateTimeOffset.UtcNow.Ticks / 10000 - 62135596800000L; // 获取当前时间的毫秒级时间戳 + } + + private long WaitNextMillis(long lastTimestamp) + { + while (GetTimestamp() <= lastTimestamp) ; // 等待下一毫秒的时间戳 + + return GetTimestamp(); // 返回新的时间戳 + } + } + + +} diff --git a/src/Khd.Core.Wcs/Global/StaticData.cs b/src/Khd.Core.Wcs/Global/StaticData.cs new file mode 100644 index 0000000..44bf156 --- /dev/null +++ b/src/Khd.Core.Wcs/Global/StaticData.cs @@ -0,0 +1,79 @@ +//using CMS.Model; +using Jc.SnowId; +using Khd.Core.Domain.Dto; +using Khd.Core.Domain.Models; + +namespace Khd.Core.Wcs.Global +{ + public static class StaticData + { + /// + /// 物料信息 + /// + public static List MateriaList = new List(); + /// + /// 库区信息 + /// + public static List BaseAreaList = new List(); + /// + /// 站台信息 + /// + public static List SiteNodeList = new List(); + /// + /// 小车信息 + /// + public static List CarList = new List(); + /// + /// 点位信息 + /// + //public static List NodeSettingList = new List(); + /// + /// 点位信息 + /// + public static List BasePlcpointList = new List(); + public static List WcsTask = new List(); + public static List WcsTaskLog = new List(); + public static List WmsBaseWarehouse = new List(); + public static List WmsWarehouseMaterial = new List(); + public static List MesBasePalletInfo = new List(); + public static List BaseDictionary = new List(); + // 记录实时报警记录缓存 + public static List HositerDmsRecordAlarmTimes = new List(); + + private static object baseEquipLock = new object(); + private static List _baseEquip = new List(); + public static List BaseEquip + { + get + { + lock (baseEquipLock) + { + return _baseEquip; + } + } + set + { + lock (baseEquipLock) + { + _baseEquip = value; + } + } + } + public static List WcsCmd = new List(); + public static List WcsCmdLog = new List(); + public static List WcsStock = new List(); + public static List WcsInWareOrder = new List(); + public static List WcsOutWareOrder = new List(); + public static List basePlcs = new List(); + public static List PlcConfigs { get; set; } + public static int DeleteLogDay { get; internal set; } + public static List DmsBaseAlarmRuleList { get; set; } + public static IEnumerable LocationToPlcList { get; internal set; } + + public static List BigContainerCodes = new List() { "JYHB01020001", "JYHB01020002", "JYHB01020003", "JYHB01020004" }; + + public static Dictionary> PlcPoints = new Dictionary>(); + public static Dictionary PlcDic = new Dictionary(); + public static JcSnowId SnowId = new JcSnowId(); + } +} diff --git a/src/Khd.Core.Wcs/Khd.Core.Wcs.csproj b/src/Khd.Core.Wcs/Khd.Core.Wcs.csproj new file mode 100644 index 0000000..b588c47 --- /dev/null +++ b/src/Khd.Core.Wcs/Khd.Core.Wcs.csproj @@ -0,0 +1,50 @@ + + + + Exe + net6.0 + enable + enable + + + + + + + + + + + + + + + + + + + + + + + + + + + Always + + + Always + + + + + + + + + + + + + diff --git a/src/Khd.Core.Wcs/MainCentralControl.cs b/src/Khd.Core.Wcs/MainCentralControl.cs new file mode 100644 index 0000000..6822d32 --- /dev/null +++ b/src/Khd.Core.Wcs/MainCentralControl.cs @@ -0,0 +1,127 @@ +using Jc.SnowId; +using Khd.Core.Domain.Dto.TaskType; +using Khd.Core.Domain.Models; +using Khd.Core.EntityFramework; +using Khd.Core.Library; +using Khd.Core.Wcs.Global; +using Khd.Core.Wcs.Wcs; +using Microsoft.EntityFrameworkCore; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; +using System.Data; +using Z.EntityFramework.Plus; + +namespace Khd.Core.Wcs +{ + public class MainCentralControl + { + public static object QingKongDianWei = 0; + public static object WcsChuLiWanCheng = 1; + public static object WcsMoRenQuXiang = 1; + + private readonly IHost _host; + + /// + /// 构造函数 + /// + /// + public MainCentralControl(IHost host) + { + this._host = host; + } + + /// + /// 启动程序 + /// + public void Start() + { + + LoggerUtils logger = new LoggerUtils(); + using var scope = _host.Services.CreateScope(); + var dbContext = scope.ServiceProvider.GetRequiredService(); + try + { + StaticData.BasePlcpointList = dbContext.BasePlcpoint.Where(t => t.isDelete == 0).ToList();//设备交互用 + StaticData.basePlcs = dbContext.BasePlc.ToList();//陈工Agv和设备信息推送 + StaticData.BaseEquip = dbContext.BaseEquip.ToList();//设备信息 + StaticData.BaseDictionary = dbContext.BaseDictionary.ToList();//字典表,Agv任务模板 + StaticData.DmsBaseAlarmRuleList = dbContext.DmsBaseAlarmRule.ToList(); + StaticData.HositerDmsRecordAlarmTimes = dbContext.DmsRecordAlarmTime.ToList(); + foreach (var plcConfig in StaticData.PlcConfigs) + { + if (!StaticData.PlcDic.Any(t => t.Key == plcConfig.Code)) + { + Plc.S7.Plc plc; + plc = new Plc.S7.Plc(plcConfig.CpuType, plcConfig.IP, plcConfig.Port, plcConfig.Rack, plcConfig.Slot); + try + { + plc.Open(); + Console.WriteLine(DateTime.Now + ":连接PLC:" + plcConfig.IP); + } + catch + { + Console.WriteLine(DateTime.Now + ":连接Plc" + plcConfig.IP + "失败~~~~~~~"); + } + StaticData.PlcDic.TryAdd(plcConfig.Code, plc); + } + } + //创建定时器 + SystemTimer systemTimer = new(_host); + systemTimer.Start(); + //创建任务 + CreateTaskByRecord createTaskByRecord = new(_host); + createTaskByRecord.StartPoint(); + + //一楼提升机以及接驳位 + FirstFloor firstFloor = new(_host); + firstFloor.StartPoint(); + + //二层接驳位 + SecondFloorPoint secondFloorPoint = new(_host, 2); + secondFloorPoint.StartPoint(); + + ////二层AGV + SecondFloorAGV secondFloorAGV = new(_host, 2); + secondFloorAGV.StartPoint(); + + // //二楼线体 + SecondFloorLine secondFloorLine = new(_host, 2); + secondFloorLine.StartPoint(); + + //三层接驳位 + ThirdFloorPoint thirdFloorPoint = new(_host, 3); + thirdFloorPoint.StartPoint(); + + // 三层AGV + ThirdFloorAGV thirdFloorAGV = new(_host, 3); + thirdFloorAGV.StartPoint(); + + //四楼接驳位 + FourthFloorPoint fourthFloorPoint = new(_host, 4); + fourthFloorPoint.StartPoint(); + + //五层接驳位 + FiveFloorPoint fifthFloorPoint = new(_host, 5); + fifthFloorPoint.StartPoint(); + + //五层CTU + FiveFloorCTU fiveFloorCTU = new(_host, 5); + fiveFloorCTU.StartPoint(); + + //五层AGV + FiveFloorAGV fifthFloorAGV = new(_host, 5); + fifthFloorAGV.StartPoint(); + + ////背负式Agv + FiveFloorBearAgv fiveFloorBearAgv = new(_host, 5); + fiveFloorBearAgv.StartPoint(); + } + catch (Exception ex) + { + Console.WriteLine(ex.Message); + logger.Error(ex.Message + "\n" + ex.StackTrace); + } + } + + } +} diff --git a/src/Khd.Core.Wcs/NLog.config b/src/Khd.Core.Wcs/NLog.config new file mode 100644 index 0000000..46ffac4 --- /dev/null +++ b/src/Khd.Core.Wcs/NLog.config @@ -0,0 +1,21 @@ + + + +
+ + + + + + + + + . + + + + + + + + diff --git a/src/Khd.Core.Wcs/Program.cs b/src/Khd.Core.Wcs/Program.cs new file mode 100644 index 0000000..444d5e7 --- /dev/null +++ b/src/Khd.Core.Wcs/Program.cs @@ -0,0 +1,103 @@ +using Khd.Core.Domain.Models; +using Khd.Core.EntityFramework; +using Khd.Core.Library; +using Khd.Core.Wcs; +using Khd.Core.Wcs.Global; +using Microsoft.EntityFrameworkCore; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; +using System.Diagnostics; + +internal class Program +{ + private static LoggerUtils _logger = new LoggerUtils(); + private static void Main(string[] args) + { + Thread.CurrentThread.Name = "Main"; + Console.ForegroundColor = ConsoleColor.Yellow; + Init(); //初始化加载配置文件 + AppDomain.CurrentDomain.UnhandledException += GlobalExceptionHandler; //全局异常捕获 + try + { + Process[] processes = Process.GetProcessesByName("Khd.Core.Wcs"); + if (processes.Length > 1) + { + Console.Write("系统已经启动,请勿重复启动1"); + Console.ReadLine(); + return; + } + var mutex = new Mutex(true, "Khd.Core.Wcs", out bool ret); + if (ret) + { + IHost host = CreateHostBuilder(args).Build(); + + _logger.Info("系统启动开始"); + Console.WriteLine($"{DateTime.Now}:系统启动开始"); + + MainCentralControl main = new(host); + main.Start(); + mutex.ReleaseMutex(); // 释放 Mutex + + _logger.Info("系统启动成功"); + Console.WriteLine($"{DateTime.Now}:系统启动成功"); + + while (true) + { + Console.ReadLine(); + } + } + else + { + Console.Write("系统重复开启,请先关闭之前窗口"); + Console.ReadLine(); + } + } + catch (Exception ex) + { + Console.Write("系统启动异常:" + ex.Message + "\n" + ex.StackTrace); + _logger.Error(ex.Message + "\n" + ex.StackTrace); + } + + } + private static void GlobalExceptionHandler(object sender, UnhandledExceptionEventArgs e) + { + //当前线程名称 + Thread.CurrentThread.Name = "Error"; + if (e.ExceptionObject is Exception exception) + { + Console.WriteLine("全局异常捕获:"); + Console.WriteLine(exception.Message); + Console.WriteLine(exception.StackTrace); + _logger.Info("全局异常捕获:" + exception.Message + "\n" + exception.StackTrace); + } + else + { + Console.WriteLine("未知异常捕获:"); + Console.WriteLine(e.ExceptionObject); + _logger.Info("未知异常捕获:" + e.ExceptionObject); + } + } + + /// + /// 初始化加载配置文件 + /// + private static void Init() + { + IConfigurationRoot configuration = new ConfigurationBuilder() + .SetBasePath(AppDomain.CurrentDomain.BaseDirectory) + .AddJsonFile("appsettings.json") + .Build(); + + StaticData.PlcConfigs = configuration.GetSection("PlcConfigs").Get>(); + ConnectionStrings.ConnectionString = configuration["ConnectionStrings:DefaultConnection"]; + StaticData.DeleteLogDay = Convert.ToInt32(configuration["DeleteLogDays"] ?? "10"); + } + private static IHostBuilder CreateHostBuilder(string[] args) => + Host.CreateDefaultBuilder(args) + .ConfigureServices((_, services) => + { + services.AddDbContext(options => + options.UseMySql(ConnectionStrings.ConnectionString, new MySqlServerVersion(new Version(8, 0, 31))), ServiceLifetime.Scoped); + }); +} diff --git a/src/Khd.Core.Wcs/SystemData.cs b/src/Khd.Core.Wcs/SystemData.cs new file mode 100644 index 0000000..d46c655 --- /dev/null +++ b/src/Khd.Core.Wcs/SystemData.cs @@ -0,0 +1,287 @@ +using Khd.Core.Domain.Dto.waring; +using Khd.Core.Domain.Models; +using Khd.Core.EntityFramework; +using Khd.Core.Library.Mapper; +using Khd.Core.Wcs.Global; +using Z.EntityFramework.Plus; + +namespace Khd.Core.Wcs +{ + public class SystemData + { + public readonly static int maxTray = 10; + + private static long _serialNo { get; set; } = 1; + + private static object serialLock = new object(); + + + + public static long GetSerialNo(DefaultDbContext dbContext) + { + lock (serialLock) + { + List list = dbContext.WcsTask.Select(t => t.serialNo).ToList(); + while (list.Contains(_serialNo)) + { + _serialNo++; + if (_serialNo > 9999) + { + _serialNo = 1; + } + } + return _serialNo; + } + } + public static object outStockLock = new object(); + + /// + /// 出入库锁定浅库位 + /// + /// + /// + public static void LockOutLocation(WmsBaseLocation wmsBaseLocation, DefaultDbContext dbContext) + { + if (wmsBaseLocation.locDeep == 1) + { + WmsBaseLocation? wmsLocation = dbContext.WmsBaseLocation + .Where(t => t.warehouseId == wmsBaseLocation.warehouseId) + .Where(t => t.locDeep == 2 && t.locColumn == wmsBaseLocation.locColumn && t.locRow == (wmsBaseLocation.locRow % 2 == 0 ? wmsBaseLocation.locRow - 1 : wmsBaseLocation.locRow + 1)).FirstOrDefault(); + if (wmsLocation != null && wmsLocation.locationStatus == "1") + { + wmsLocation.locationStatus = "2"; + dbContext.Update(wmsLocation); + } + } + } + + /// + /// 出入库解锁浅库位 + /// + /// + /// + public static void UnLockOutLocation(WmsBaseLocation wmsBaseLocation, DefaultDbContext dbContext) + { + if (wmsBaseLocation.locDeep == 1) + { + WmsBaseLocation? wmsLocation = dbContext.WmsBaseLocation + .Where(t => t.warehouseId == wmsBaseLocation.warehouseId) + .Where(t => t.locDeep == 2 && t.locColumn == wmsBaseLocation.locColumn && t.locRow == (wmsBaseLocation.locRow % 2 == 0 ? wmsBaseLocation.locRow - 1 : wmsBaseLocation.locRow + 1)).FirstOrDefault(); + if (wmsLocation != null && wmsLocation.locationStatus != "3" && wmsLocation.locationStatus != "9") + { + wmsLocation.locationStatus = "1"; + dbContext.Update(wmsLocation); + } + } + wmsBaseLocation.locationStatus = "1"; + + } + + /// + /// 报警库位 + /// + public static void AlarmLocation(WmsBaseLocation wmsBaseLocation, DefaultDbContext dbContext) + { + if (wmsBaseLocation.locDeep == 2) + { + WmsBaseLocation? wmsLocation = dbContext.WmsBaseLocation.Where(t => t.locDeep == 1 && t.locRow == wmsBaseLocation.locRow && t.locColumn == (wmsBaseLocation.locColumn % 2 == 0 ? wmsBaseLocation.locColumn - 1 : wmsBaseLocation.locColumn + 1)).FirstOrDefault(); + if (wmsLocation != null && wmsLocation.locationStatus != "3") + { + wmsLocation.locationStatus = "8"; + wmsLocation.ExceptionDesc = "外侧库位异常导致内测库位异常"; + dbContext.Update(wmsLocation); + } + } + } + + /// + /// 解除报警库位 + /// + public static void UnAlarmLocation(WmsBaseLocation wmsBaseLocation, DefaultDbContext dbContext) + { + if (wmsBaseLocation.locDeep == 2) + { + WmsBaseLocation? wmsLocation = dbContext.WmsBaseLocation.Where(t => t.locDeep == 1 && t.locRow == wmsBaseLocation.locRow && t.locColumn == (wmsBaseLocation.locColumn % 2 == 0 ? wmsBaseLocation.locColumn - 1 : wmsBaseLocation.locColumn + 1)).FirstOrDefault(); + if (wmsLocation != null && wmsLocation.locationStatus == "8") + { + wmsLocation.locationStatus = "1"; + dbContext.Update(wmsLocation); + } + } + } + + public static void InsertWaringLog(DefaultDbContext dbContext, WaringType WaringType, string message = "") + { + try + { + var alarmRule = StaticData.DmsBaseAlarmRuleList.Where(t => t.AlarmRuleId == (long)WaringType).FirstOrDefault(); + if (alarmRule != null) + { + var alarmTime = dbContext.DmsRecordAlarmTime.Where(t => t.AlarmRuleId == (long)WaringType).FirstOrDefault(); + if (alarmTime == null) + { + alarmTime = new DmsRecordAlarmTime() + { + AlarmId = StaticData.SnowId.NextId(), + AlarmRuleId = (long)WaringType, + DeviceId = alarmRule.DeviceId, + AlarmBeginTime = DateTime.Now, + ContinueTime = alarmRule.ContinueTime, + AlarmReason = alarmRule.AlarmReason, + HandleSuggest = alarmRule.HandleSuggest, + CreateBy = "WCS", + CreateTime = DateTime.Now, + AlarmData = message + }; + var dmsRecordAlarmInfo = CoreMapper.Map(alarmTime); + dmsRecordAlarmInfo.NoticeStatus = "0"; + dmsRecordAlarmInfo.AlarmStatus = "0"; + dbContext.Add(dmsRecordAlarmInfo); + dbContext.Add(alarmTime); + dbContext.SaveChanges(); + } + } + } + catch + { + + } + + } + + public static void InsertWaringLog(DefaultDbContext dbContext, string WaringType, string message = "") + { + try + { + var alarmRule = StaticData.DmsBaseAlarmRuleList.Where(t => t.AlarmReason == WaringType).FirstOrDefault(); + if (alarmRule != null) + { + // var alarmTime = dbContext.DmsRecordAlarmTime.Where(t => t.AlarmRuleId == alarmRule.AlarmRuleId).FirstOrDefault(); + var alarmTime = StaticData.HositerDmsRecordAlarmTimes.Where(t => t.AlarmRuleId == alarmRule.AlarmRuleId).FirstOrDefault(); + if (alarmTime == null) + { + alarmTime = new DmsRecordAlarmTime() + { + AlarmId = StaticData.SnowId.NextId(), + AlarmRuleId = alarmRule.AlarmRuleId, + DeviceId = alarmRule.DeviceId, + AlarmBeginTime = DateTime.Now, + ContinueTime = alarmRule.ContinueTime, + AlarmReason = alarmRule.AlarmReason, + HandleSuggest = alarmRule.HandleSuggest, + CreateBy = "WCS", + CreateTime = DateTime.Now, + AlarmData = message + }; + var dmsRecordAlarmInfo = CoreMapper.Map(alarmTime); + dmsRecordAlarmInfo.NoticeStatus = "0"; + dmsRecordAlarmInfo.AlarmStatus = "0"; + dbContext.Add(dmsRecordAlarmInfo); + dbContext.Add(alarmTime); + dbContext.SaveChanges(); + StaticData.HositerDmsRecordAlarmTimes.Add(alarmTime); + } + } + } + catch + { + + } + + } + + + + public static void DeleteWaringLog(DefaultDbContext dbContext, WaringType WaringType) + { + try + { + var alarmTime = dbContext.DmsRecordAlarmTime.Where(t => t.AlarmRuleId == (long)WaringType).FirstOrDefault(); + if (alarmTime != null) + { + dbContext.DmsRecordAlarmTime.Where(t => t.AlarmId == alarmTime.AlarmId).Delete(); + dbContext.DmsRecordAlarmInfo.Where(t => t.AlarmId == alarmTime.AlarmId) + .Update(t => new DmsRecordAlarmInfo() { AlarmStatus = "2" }); + } + } + catch + { + } + + } + + + public static void DeleteWaringLog(DefaultDbContext dbContext, string WaringType) + { + try + { + // var alarmTime = dbContext.DmsRecordAlarmTime.Where(t => t.AlarmReason == WaringType).FirstOrDefault(); + var alarmTime = StaticData.HositerDmsRecordAlarmTimes.Where(t => t.AlarmReason == WaringType).FirstOrDefault(); + if (alarmTime != null) + { + dbContext.DmsRecordAlarmTime.Where(t => t.AlarmId == alarmTime.AlarmId).Delete(); + dbContext.DmsRecordAlarmInfo.Where(t => t.AlarmId == alarmTime.AlarmId) + .Update(t => new DmsRecordAlarmInfo() { AlarmStatus = "2" }); + StaticData.HositerDmsRecordAlarmTimes.Remove(alarmTime); + } + } + catch + { + } + + } + + + public static void SendPlcLocation(WmsBaseLocation wmsBaseLocation) + { + Task.Run(() => + { + try + { + var locationPlcDto = StaticData.LocationToPlcList.Where(t => t.Id == wmsBaseLocation.locationId).FirstOrDefault(); + if (locationPlcDto != null) + { + if (wmsBaseLocation != null && !string.IsNullOrEmpty(wmsBaseLocation.containerCode)) + { + if (wmsBaseLocation.warehouseId == 512) + { + if (wmsBaseLocation.ContainerStatus == "1") + { + StaticData.PlcDic[2].Write(locationPlcDto.Address, true); + } + else + { + StaticData.PlcDic[2].Write(locationPlcDto.Address, false); + } + } + else + { + StaticData.PlcDic[2].Write(locationPlcDto.Address, true); + } + } + else + { + StaticData.PlcDic[2].Write(locationPlcDto.Address, false); + } + } + } + catch + { + + } + }); + + } + + internal static WmsBaseLocation? GetLowerLocation(WmsBaseLocation wmslocation, DefaultDbContext dbContext) + { + return dbContext.WmsBaseLocation.Where(t => t.warehouseId == wmslocation.warehouseId) + .Where(t => t.locDeep == 2 && t.locColumn == wmslocation.locColumn && t.locRow == (wmslocation.locRow % 2 == 0 ? wmslocation.locRow - 1 : wmslocation.locRow + 1)).FirstOrDefault(); + } + + public readonly static object SecondTaskLock = new(); + public readonly static object ThirdTaskLock = new(); + public readonly static object FiveTaskLock = new(); + + } +} diff --git a/src/Khd.Core.Wcs/ThriftServer/WcsServer.cs b/src/Khd.Core.Wcs/ThriftServer/WcsServer.cs new file mode 100644 index 0000000..6796c97 --- /dev/null +++ b/src/Khd.Core.Wcs/ThriftServer/WcsServer.cs @@ -0,0 +1,26 @@ +namespace ThriftService +{ + public class WcsServer : WcsThrift.Iface + { + public delegate string deletehello(string name); + public deletehello helloEvent; + public string hello(string name) + { + if (helloEvent != null) + { + return helloEvent(name); + } + return ""; + } + public delegate string deleteSendCar(List carlist, string order_code, string amount); + public deleteSendCar SendCarEvent; + public string SendCar(List carlist, string order_code, string amount) + { + if (SendCarEvent != null) + { + return SendCarEvent(carlist, order_code, amount); + } + return ""; + } + } +} diff --git a/src/Khd.Core.Wcs/Wcs/BackUpData.cs b/src/Khd.Core.Wcs/Wcs/BackUpData.cs new file mode 100644 index 0000000..f474d77 --- /dev/null +++ b/src/Khd.Core.Wcs/Wcs/BackUpData.cs @@ -0,0 +1,78 @@ +using Khd.Core.EntityFramework; +using Khd.Core.Library; +using Microsoft.EntityFrameworkCore; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; +using System.Timers; +namespace Khd.Core.Wcs.Wcs +{ + public class BackUpData + { + private readonly IHost _host; + public BackUpData(IHost host) + { + this._host = host; + } + /// + /// 启动线程 + /// + public void StartPoint() + { + Thread OrderBakThread = new Thread(MonitorInLocatorPoint); + OrderBakThread.Start(); + } + + public void MonitorInLocatorPoint() + { + // 创建一个定时器对象,设置时间间隔为24小时 + System.Timers.Timer timer = new System.Timers.Timer(24 * 60 * 60 * 1000); // 1000毫秒 = 1秒 + //timer = new System.Timers.Timer(10*1000); // 1000毫秒 = 1秒 + + // 添加一个事件处理程序,当定时器间隔结束时调用方法 + timer.Elapsed += OnTimerElapsed; + + // 启动定时器 + timer.Enabled = true; + } + + /// + /// 定时方法 + /// + /// + /// + private void OnTimerElapsed(object? sender, ElapsedEventArgs e) + { + LoggerUtils _logger = new LoggerUtils(); + try + { + using var scope = _host.Services.CreateScope(); + using var dbContext = scope.ServiceProvider.GetRequiredService(); + string sqlQuery = @$"INSERT INTO + base_production_order_split_bak + (id,site_code, line_code, line_name, order_code,prod_code,prod_desc,IsOver,est,Quantity,production_sequence) + SELECT + id,site_code, line_code, line_name, order_code,prod_code,prod_desc,IsOver,est,Quantity,production_sequence + FROM base_production_order_split + where + IsOver = 1 + and + est < date_add(NOW(), interval -1 DAY); + delete + FROM + base_production_order_split + WHERE + IsOver = 1 + and + est < date_add(NOW(), interval -1 DAY);"; + var ret = dbContext.Database.ExecuteSqlRaw(sqlQuery); + string saveLog = ret == 0 ? "备份任务SQL语句存在问题!" : "备份任务SQL语句执行成功!"; + _logger.Info($"定时备份任务日志记录 >>> {saveLog}"); + } + catch (Exception ex) + { + _logger.Info($"定时备份任务方法报错 >>> {ex.Message}"); + } + + } + } +} diff --git a/src/Khd.Core.Wcs/Wcs/CreateTaskByRecord.cs b/src/Khd.Core.Wcs/Wcs/CreateTaskByRecord.cs new file mode 100644 index 0000000..0adfe0b --- /dev/null +++ b/src/Khd.Core.Wcs/Wcs/CreateTaskByRecord.cs @@ -0,0 +1,3628 @@ +using Khd.Core.Domain.Dto.TaskType; +using Khd.Core.Domain.Dto.waring; +using Khd.Core.Domain.Models; +using Khd.Core.EntityFramework; +using Khd.Core.Library; +using Khd.Core.Library.Mapper; +using Khd.Core.Wcs.Global; +using Masuit.Tools; +using Microsoft.CodeAnalysis; +using Microsoft.EntityFrameworkCore; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; +using Newtonsoft.Json; +using SixLabors.ImageSharp; +using System.Data; +using System.Drawing.Text; +using Thrift.Protocol; +using Z.EntityFramework.Plus; + +namespace Khd.Core.Wcs.Wcs +{ + /// + /// 根据出入库记录创建出入库任务 + /// + public class CreateTaskByRecord + { + private readonly LoggerUtils _logger = new LoggerUtils(); + private readonly IHost _host; + public CreateTaskByRecord(IHost host) + { + this._host = host; + } + + /// + /// 启动上件扫描监听 + /// + public void StartPoint() + { + //var createRemoveThread = new Thread(CreateRemoveLogic); + //createRemoveThread.IsBackground = true; + //createRemoveThread.Name = "CreateRemoveLogic"; + //createRemoveThread.Start(); + + //二楼、五楼人工指定库位成品出库任务 + var CreateProductTaskByLocationCodeThread = new Thread(CreateProductTaskByLocationCodeLogic); + CreateProductTaskByLocationCodeThread.IsBackground = true; + CreateProductTaskByLocationCodeThread.Name = "CreateFiveProductTaskLogic"; + CreateProductTaskByLocationCodeThread.Start(); + + + //创建退库任务 + var stockReturnThread = new Thread(StockReturnLogic); + stockReturnThread.IsBackground = true; + stockReturnThread.Name = "StockReturnLogic"; + stockReturnThread.Start(); + + // PDA移库 + var moveThread = new Thread(MoveThreadLogic); + moveThread.IsBackground = true; + moveThread.Name = "MoveThreadLogic"; + moveThread.Start(); + + // 叫空托盘 3-2楼 + var createEmtpyThread = new Thread(CreateEmptyLogic); + createEmtpyThread.IsBackground = true; + createEmtpyThread.Name = "CreateEmptyLoic"; + createEmtpyThread.Start(); + //背负式Agv返库任务 + var createBearAgvReturnThread = new Thread(CreateBearAgvReturnLogic); + createBearAgvReturnThread.IsBackground = true; + createBearAgvReturnThread.Name = "CreateBearAgvReturnLogic"; + createBearAgvReturnThread.Start(); + //五楼半成品入库任务 + var createFiveProductInTaskThread = new Thread(CreateFiveProductInTaskLogic); + createFiveProductInTaskThread.IsBackground = true; + createFiveProductInTaskThread.Name = "CreateFiveProductInTaskLogic"; + createFiveProductInTaskThread.Start(); + //五楼成品出库任务 + var createFiveProductTaskThread = new Thread(CreateFiveProductTaskLogic); + createFiveProductTaskThread.IsBackground = true; + createFiveProductTaskThread.Name = "CreateFiveProductTaskLogic"; + createFiveProductTaskThread.Start(); + //五楼CTU出库任务以及原材料出库任务 + var createRawTaskThread = new Thread(CreateRawTaskLogic); + createRawTaskThread.IsBackground = true; + createRawTaskThread.Name = "CreateRawTaskLogic"; + createRawTaskThread.Start(); + //五楼柜体拆分返库任务 + var createRawInThread = new Thread(CreateRawInTaskLogic); + createRawInThread.IsBackground = true; + createRawInThread.Name = "CreateRawInTaskLogic"; + createRawInThread.Start(); + //三楼去翻转机任务 + var createThirdOutTaskThread = new Thread(CreateThirdOutTaskLogic); + createThirdOutTaskThread.IsBackground = true; + createThirdOutTaskThread.Name = "CreateThirdOutTaskLogic"; + createThirdOutTaskThread.Start(); + //二楼成品出库任务 + var CreateSecondProductTaskThread = new Thread(CreateSecondProductTaskLogic); + CreateSecondProductTaskThread.IsBackground = true; + CreateSecondProductTaskThread.Name = "CreateSecondProductTaskLogic"; + CreateSecondProductTaskThread.Start(); + //三楼托盘收集架满5个或10个时出库合盘任务 + var createEmptyTrayThread = new Thread(CreateEmptyTrayLogic); + createEmptyTrayThread.IsBackground = true; + createEmptyTrayThread.Name = "CreateEmptyTrayLogic"; + createEmptyTrayThread.Start(); + //二楼废品区人工调度任务 + var createThirdWasterTaskThread = new Thread(CreateThirdWasterTaskLogic); + createThirdWasterTaskThread.IsBackground = true; + createThirdWasterTaskThread.Name = "CreateThirdWasterTaskLogic"; + createThirdWasterTaskThread.Start(); + //背负式退库 + var BackReturnTaskThread = new Thread(BackReturnTaskLogic); + BackReturnTaskThread.IsBackground = true; + BackReturnTaskThread.Name = "BackReturnTaskLogic"; + BackReturnTaskThread.Start(); + Console.WriteLine(DateTime.Now + ":出库任务监听启动成功"); + _logger.Info("出库任务监听启动成功"); + } + + /// + /// 退库 + /// + /// + private void StockReturnLogic(object? obj) + { + using var scope = _host.Services.CreateScope(); + using var dbContext = scope.ServiceProvider.GetRequiredService(); + BaseEquip thirdAgv = StaticData.BaseEquip.First(t => t.objid == 9); + BaseEquip fiveAgv = StaticData.BaseEquip.First(t => t.objid == 28); + BaseEquip firstLine = StaticData.BaseEquip.First(t => t.objid == 1); + BaseEquip thirdLine = StaticData.BaseEquip.First(t => t.objid == 3); + BaseEquip fiveLine = StaticData.BaseEquip.First(t => t.objid == 5); + while (true) + { + try + { + dbContext.ChangeTracker.Clear(); + var rawOutStock = dbContext.WmsRawOutstock + .Where(t => t.executeStatus == "0") + .Where(t => t.outstockAmount > t.realOutstockAmount) + .Where(t => t.taskType == "5") + .Where(t => t.operationType == "0") + .Where(t => t.auditStatus == "1") + .ToList(); + + //浅库位退库单往前排序,尽量避免移库操作 + if (rawOutStock != null && rawOutStock.Count > 0) + { + var locations = dbContext.WmsBaseLocation + .Where(t => rawOutStock.Select(x => x.locationCode).Contains(t.locationCode)) + .AsEnumerable() + .OrderBy(x => x.locDeep == 2 ? 0 : 99) + .Select((loc, index) => new { loc.locationCode, Index = index }) + .ToDictionary(item => item.locationCode, item => item.Index); + + rawOutStock = rawOutStock.OrderBy(x => locations[x.locationCode]).ToList(); + //var locationOrder = dbContext.WmsBaseLocation + // .Where(t => rawOutStock.Select(x => x.locationCode).Contains(t.locationCode)) + // .OrderBy(x => x.locDeep == 2 ? 0 : 99) + // .Select((loc, index) => new { loc.locationCode, Index = index }) + // .ToDictionary(item => item.locationCode, item => item.Index); + + //rawOutStock = rawOutStock.OrderBy(x => locationOrder[x.locationCode]).ToList(); + } + foreach (var item in rawOutStock) + { + int taskType = 0; + int removeType = 0; + BaseEquip? agvEquip = null; + BaseEquip? EndEquip = null; + if (item.warehouseId == 311) + { + agvEquip = thirdAgv; + removeType = StaticTaskType.ThirdRemove; + taskType = StaticTaskType.ThirdStockReturnTask; + EndEquip = thirdLine; + } + else if (item.warehouseId == 511) + { + agvEquip = fiveAgv; + removeType = StaticTaskType.FiveRemove; + taskType = StaticTaskType.FiveStockReturnTask; + EndEquip = fiveLine; + } + if (agvEquip != null && EndEquip != null) + { + bool hasTask = dbContext.WcsTask.Where(t => t.nextPointId == agvEquip.objid).Where(t => t.useFlag == 1).Any(); + if (hasTask) + { + continue; + } + var wmsBaseLocation = dbContext.WmsBaseLocation.Where(t => t.locationCode == item.locationCode).FirstOrDefault(); + if (wmsBaseLocation != null) + { + if (!string.IsNullOrEmpty(wmsBaseLocation.containerCode)) // && wmsBaseLocation.locationStatus == "1" + { + // 目标库位处于深库位,判断是否需要移库浅库位 + if (wmsBaseLocation.locDeep == 1) + { + int? row = 0; + if (wmsBaseLocation.locRow % 2 == 1) + { + row = wmsBaseLocation.locRow + 1; + } + else + { + row = wmsBaseLocation.locRow - 1; + } + var fromBaseLocation = SystemData.GetLowerLocation(wmsBaseLocation, dbContext);//浅库位 + if (fromBaseLocation != null && fromBaseLocation.locationStatus == "1") + { + if (!string.IsNullOrEmpty(fromBaseLocation.containerCode))//有库存 + { + #region 找寻移库目标库位 + // 寻找移库目的库位 + WmsBaseLocation? toLocation = null; + var AllWmsBaseLocations = dbContext.WmsBaseLocation + .Where(t => t.activeFlag == "1") + .Where(t => t.delFlag == "0") + .Where(t => t.locationScrapType == "1") + .Where(t => t.warehouseId == fromBaseLocation.warehouseId) + .Where(t => t.locationStatus == "1").ToList(); + var moveLocationList = AllWmsBaseLocations.Where(t => t.warehouseId == fromBaseLocation.warehouseId) + .Where(t => t.warehouseId != fromBaseLocation.locationId) + .Where(t => string.IsNullOrEmpty(t.containerCode)).OrderBy(t => t.locDeep).ToList(); + + foreach (WmsBaseLocation itemLocation in moveLocationList) + { + + if (itemLocation.locDeep == 1) + { + bool hasLocation = AllWmsBaseLocations + .Where(t => t.locRow == (itemLocation.locRow % 2 == 1 ? (itemLocation.locRow + 1) : (itemLocation.locRow - 1))) + .Where(t => t.locColumn == itemLocation.locColumn) + .Where(t => t.locationStatus == "1" && string.IsNullOrEmpty(t.containerCode)) + .Any(); + if (!hasLocation) + { + Console.WriteLine(DateTime.Now + $":目标库位的浅库位库位状态异常,无法移库"); + _logger.Info($"目标库位的浅库位库位状态异常,无法移库"); + continue; + } + else + { + // 找到可以移库的目标库位 + toLocation = itemLocation; + break; + } + + } + else + { + // 找到可以移库的目标库位 + toLocation = itemLocation; + break; + } + + } + if (toLocation == null) + { + // 找寻下一个可出库库存 + continue; + } + + var RemoveTask = new WcsTask() + { + objid = StaticData.SnowId.NextId(), + taskType = removeType, + containerNo = fromBaseLocation.containerCode, + createBy = "WCS", + createTime = DateTime.Now.AddSeconds(-10), + taskStatus = 0, + currPointId = fromBaseLocation.locationId, + currPointNo = fromBaseLocation.locationCode, + nextPointId = agvEquip.objid, + nextPointNo = agvEquip.equipNo, + endPointId = toLocation.locationId, + endPointNo = toLocation.locationCode, + equipmentNo = agvEquip.equipNo, + useFlag = 1, + qty = 1 + }; + SystemData.LockOutLocation(toLocation, dbContext); + SystemData.LockOutLocation(fromBaseLocation, dbContext); + toLocation.locationStatus = "4"; + toLocation.updateBy = "WCS"; + toLocation.updateTime = DateTime.Now; + fromBaseLocation.updateBy = "WCS"; + fromBaseLocation.updateTime = DateTime.Now; + fromBaseLocation.locationStatus = "4"; + dbContext.Update(toLocation); + dbContext.Update(fromBaseLocation); + dbContext.Add(RemoveTask); + WcsTaskLog wcsTaskLog = CoreMapper.Map(RemoveTask); + dbContext.Add(wcsTaskLog); + #endregion + } + else//没库存,不需要移库任务 + { + + } + } + else//库位异常 + { + continue; + } + } + } + else//没有库存 + { + continue; + } + var task = new WcsTask() + { + objid = StaticData.SnowId.NextId(), + orderId = item.rawOutstockId, + taskType = taskType, + containerNo = wmsBaseLocation.containerCode, + createBy = "WCS", + createTime = DateTime.Now.AddSeconds(-10), + taskStatus = 0, + currPointId = wmsBaseLocation.locationId, + currPointNo = wmsBaseLocation.locationCode, + nextPointId = agvEquip.objid, + nextPointNo = agvEquip.equipNo, + endPointId = EndEquip.objid, + endPointNo = EndEquip.equipNo, + equipmentNo = agvEquip.equipNo, + useFlag = 1, + fromFloorNo = agvEquip.floorNo, + floorNo = 1, + qty = 1 + }; + SystemData.LockOutLocation(wmsBaseLocation, dbContext); + wmsBaseLocation.locationStatus = "6"; + dbContext.Update(wmsBaseLocation); + dbContext.Add(task); + WcsTaskLog taskLog = CoreMapper.Map(task); + dbContext.Add(taskLog); + //创建出库任务 + item.executeStatus = "1"; + item.beginTime = DateTime.Now; + dbContext.Update(item); + dbContext.SaveChanges(); + } + } + else + { + + } + } + } + catch + { + + } + Thread.Sleep(3000); + } + } + + /// + /// PDA移库 + /// + /// + private void MoveThreadLogic(object? obj) + { + using var scope = _host.Services.CreateScope(); + using var dbContext = scope.ServiceProvider.GetRequiredService(); + BaseEquip secondAgv = StaticData.BaseEquip.First(t => t.objid == 8); + BaseEquip thirdAgv = StaticData.BaseEquip.First(t => t.objid == 9); + BaseEquip fiveAgv = StaticData.BaseEquip.First(t => t.objid == 28); + List wareHouseIds = new List + { + 231,311,511,531 + }; + while (true) + { + try + { + dbContext.ChangeTracker.Clear(); + List wmsMoves = dbContext.WmsMove.Where(t => t.AuditStatus == "1" && t.ExecuteStatus == "0") + .Where(t => wareHouseIds.Contains(t.WarehouseId)).ToList(); //.Where(t => t.OperationType == "3") + foreach (var item in wmsMoves) + { + BaseEquip agvEquip; + int staticTask; + if (item.WarehouseId == 231) + { + agvEquip = secondAgv; + staticTask = StaticTaskType.SecondRemove; + } + else if (item.WarehouseId == 311) + { + agvEquip = thirdAgv; + staticTask = StaticTaskType.ThirdRemove; + } + else + { + agvEquip = fiveAgv; + staticTask = StaticTaskType.FiveRemove; + } + bool hasTask = dbContext.WcsTask.Where(t => t.useFlag == 1 && t.nextPointId == agvEquip.objid).Any(); + if (!hasTask) + { + WmsBaseLocation? wmslocation = dbContext.WmsBaseLocation.FirstOrDefault(t => t.locationCode == item.OriLocationCode); + WmsBaseLocation? toLocation = dbContext.WmsBaseLocation.FirstOrDefault(t => t.locationCode == item.TargetLocationCode); + if (wmslocation != null && wmslocation.locDeep == 1) + { + //查询浅库位状态 + var lowerLocation = SystemData.GetLowerLocation(wmslocation, dbContext); + if (lowerLocation != null && (lowerLocation == null || lowerLocation.locationStatus != "1" || !string.IsNullOrEmpty(lowerLocation.containerCode))) + { + continue; + } + } + //if (toLocation != null && toLocation.locDeep == 1) + //{ + // //查询浅库位状态 + // var lowerLocation = SystemData.GetLowerLocation(toLocation, dbContext); + // if (lowerLocation != null && (lowerLocation == null || lowerLocation.locationStatus != "1" || !string.IsNullOrEmpty(lowerLocation.containerCode))) + // { + // continue; + // } + //} + if (wmslocation != null && toLocation != null) + { + var RemoveTask = new WcsTask() + { + objid = StaticData.SnowId.NextId(), + orderId = item.MoveId, + taskType = staticTask, + containerNo = wmslocation.containerCode, + createBy = "WCS", + createTime = DateTime.Now.AddSeconds(-10), + taskStatus = 0, + currPointId = wmslocation.locationId, + currPointNo = wmslocation.locationCode, + nextPointId = agvEquip.objid, + nextPointNo = agvEquip.equipNo, + endPointId = toLocation.locationId, + endPointNo = toLocation.locationCode, + equipmentNo = agvEquip.equipNo, + useFlag = 1, + qty = 1 + }; + WcsTaskLog wcsTaskLog = CoreMapper.Map(RemoveTask); + SystemData.LockOutLocation(toLocation, dbContext); + SystemData.LockOutLocation(wmslocation, dbContext); + wmslocation.locationStatus = "4"; + toLocation.locationStatus = "4"; + dbContext.Add(RemoveTask); + dbContext.Add(wcsTaskLog); + item.ExecuteStatus = "1"; + item.BeginTime = DateTime.Now; + dbContext.Update(item); + dbContext.SaveChanges(); + Console.WriteLine(DateTime.Now + $":创建移库任务成功:{item.OriLocationCode}--{item.TargetLocationCode}"); + _logger.Info("创建移库任务成功:" + item.OriLocationCode + "--" + item.TargetLocationCode); + } + } + } + } + catch + { + + } + Thread.Sleep(5000); + } + } + + /// + /// 3楼到2楼托盘转运 + /// + /// + private void CreateEmptyLogic(object? obj) + { + using var scope = _host.Services.CreateScope(); + using var dbContext = scope.ServiceProvider.GetRequiredService(); + BaseEquip endEquip = StaticData.BaseEquip.First(t => t.objid == 36); + while (true) + { + try + { + bool create = false; + dbContext.ChangeTracker.Clear(); + var ids = dbContext.BaseEquip.Where(t => t.equipType == 20).Select(t => t.objid).ToList(); + bool hasTask = dbContext.WcsTask.Where(t => t.endPointId == 2 || t.endPointId == 36 || ids.Contains(t.currPointId.Value)).Any(); + if (!hasTask) + { + int thirdBTray = dbContext.BaseEquip + .Where(t => t.equipType == 15) + .Where(t => t.emptyCount > 0).Count(); + List baseEquips = dbContext.BaseEquip.Where(t => t.useFlag == 1).Where(t => t.equipType == 20).ToList(); + int emptyCount = baseEquips.Where(t => t.emptyCount == 0).Count(); + int emptyC = baseEquips.Where(t => t.emptyCount > 1).Count(); + if (thirdBTray > 0) + { + if (emptyCount > 2 && thirdBTray >= 2) + { + create = true; + } + if (emptyC <= 1 && emptyCount >= 2 && thirdBTray >= 1) + { + create = true; + } + } + if (create) + { + var baseEquip = dbContext.BaseEquip.Where(t => t.equipType == 15).OrderByDescending(t => t.emptyCount).FirstOrDefault();//三楼三个周转区是否存在空托盘 + if (baseEquip != null)//如果三楼有空托盘 + { + BaseEquip ThirdLineEquip = dbContext.BaseEquip.First(t => t.objid == 3);//三楼接驳位 + BaseEquip ThirdAgvEquip = StaticData.BaseEquip.First(t => t.objid == 9);//三楼叉车 + if (ThirdLineEquip.equipStatus == 0)//三楼接驳位空闲 + { + //生成3楼Agv出库任务 + WcsTask wcsTask = new WcsTask() + { + objid = StaticData.SnowId.NextId(), + containerNo = null, + createBy = "WCS", + createTime = DateTime.Now, + floorNo = 2, + fromFloorNo = 3, + isEmpty = "1", + qty = SystemData.maxTray, + taskType = StaticTaskType.ThirdTransitToSecond, + currPointId = baseEquip.objid, + currPointNo = baseEquip.equipNo, + nextPointId = ThirdAgvEquip.objid, + nextPointNo = ThirdAgvEquip.equipNo, + endPointId = endEquip.objid, + endPointNo = endEquip.equipNo, + taskStatus = 0, + useFlag = 1, + }; + dbContext.Add(wcsTask); + WcsTaskLog wcsTaskLog = CoreMapper.Map(wcsTask); + dbContext.Add(wcsTaskLog); + dbContext.SaveChanges(); + Console.WriteLine(DateTime.Now + ":二楼码垛输送线生成3楼Agv出库任务成功:" + wcsTask.objid); + _logger.Info("二楼码垛输送线生成3楼Agv出库任务成功:" + wcsTask.objid); + } + } + } + } + } + catch + { + + } + Thread.Sleep(1000 * 60); + } + } + + /// + /// 主动移库 + /// + /// + private void CreateRemoveLogic(object? obj) + { + using var scope = _host.Services.CreateScope(); + using var dbContext = scope.ServiceProvider.GetRequiredService(); + List cannotIn = new List(); + while (true) + { + try + { + dbContext.ChangeTracker.Clear(); + var CanRemoveWmsBaseLocations = dbContext.WmsBaseLocation.Where(t => t.locationStatus == "7").ToList(); + List locationCodes = CanRemoveWmsBaseLocations.Select(t => t.locationCode).ToList(); + List CanRemoveWmsProductStocks = dbContext.WmsProductStock.Where(t => locationCodes.Contains(t.locationCode)).ToList(); + foreach (var wmsProductStock in CanRemoveWmsProductStocks) + { + BaseEquip? agvEquip = null; + if (wmsProductStock.warehouseId == 531) + { + agvEquip = StaticData.BaseEquip.First(t => t.objid == 28); + } + else if (wmsProductStock.warehouseId == 231) + { + agvEquip = StaticData.BaseEquip.First(t => t.objid == 8); + } + if (agvEquip != null) + { + bool hasTask = dbContext.WcsTask.Where(t => t.nextPointId == agvEquip.objid).Any(); + if (!hasTask) + { + WmsBaseLocation fromLocationCode = CanRemoveWmsBaseLocations.First(t => t.locationCode == wmsProductStock.locationCode); + if (wmsProductStock.warehouseId == 531 || wmsProductStock.warehouseId == 231)//成品移库 + { + var wmsBaseLocations = dbContext.WmsBaseLocation + .Where(t => t.activeFlag == "1") + .Where(t => t.delFlag == "0") + .Where(t => t.locationScrapType == "1") + .Where(t => t.locationStatus == "1") + .Where(t => t.warehouseId == wmsProductStock.warehouseId) + .ToList();//所有可用库位 + var wmsProductStocks = dbContext.WmsProductStock + .Where(t => t.warehouseId == wmsProductStock.warehouseId) + .ToList();//仓库的库存 + WmsBaseLocation? wmsBaseLocation = null; + if (wmsBaseLocations.Count > 0) + { + List containerCodes = wmsBaseLocations + .Where(t => t.locDeep == 1) + .Select(t => t.containerCode).ToList();//深库位的有托盘 + + List mesBasePalletInfos = dbContext.MesBaseBarcodeInfo + .Where(t => t.saleOrderId == (wmsProductStock.saleOrderId == null ? 0 : wmsProductStock.saleOrderId))//销售订单 + .Where(t => t.materialId == wmsProductStock.productId)//物料Id + .Where(t => containerCodes.Contains(t.palletInfoCode)).ToList();//深库位的托盘的物料等于当前任务的物料 + + var bill = from a in mesBasePalletInfos + join b in wmsBaseLocations.Where(t => t.locDeep == 1) on a.palletInfoCode equals b.containerCode + select new { b };//等于当前任务的物料的托盘的库位信息 + + var outBill = from a in bill//深库位托盘和当前任务绑定物料一致的托盘库位 + from b in wmsBaseLocations//所有库位 + where b.locDeep == 2//浅库位 + && b.locRow == (a.b.locRow % 2 == 0 ? a.b.locRow - 1 : a.b.locRow + 1) + //如果是4则找3,如果是1则找2 + && a.b.locColumn == b.locColumn//列数相同 + && string.IsNullOrEmpty(b.containerCode) + select new { a, b };//在上面的基础上获取对应托盘的外侧库位的空库位信息 + wmsBaseLocation ??= outBill.Where(t => !cannotIn.Contains(t.b.locationCode)).FirstOrDefault()?.b;//先找相同物料的外侧库位 + wmsBaseLocation ??= wmsBaseLocations.Where(t => !cannotIn.Contains(t.locationCode)).Where(t => string.IsNullOrEmpty(t.containerCode)).FirstOrDefault(t => t.locDeep == 1);//找不到再找深库位 + wmsBaseLocation ??= wmsBaseLocations.Where(t => !cannotIn.Contains(t.locationCode)).Where(t => string.IsNullOrEmpty(t.containerCode)).FirstOrDefault();//找不到再找任意库位 + if (wmsBaseLocation != null)//如果找到库位,生成入库任务 + { + if (wmsBaseLocation.locDeep == 1) + { + bool hasLocation = wmsBaseLocations + .Where(t => t.locRow == (wmsBaseLocation.locRow % 2 == 1 ? (wmsBaseLocation.locRow + 1) : (wmsBaseLocation.locRow - 1))) + .Where(t => t.locColumn == wmsBaseLocation.locColumn) + .Any(); + if (!hasLocation) + { + cannotIn.Add(wmsBaseLocation.locationCode); + Console.WriteLine(DateTime.Now + $":目标库位{cannotIn.Join(",")}的浅库位库位状态异常,无法移库"); + _logger.Info($"目标库位{cannotIn.Join(",")}的浅库位库位状态异常,无法移库"); + continue; + } + } + var wcsTask = new WcsTask() + { + objid = StaticData.SnowId.NextId(), + currPointId = fromLocationCode.locationId, + currPointNo = fromLocationCode.locationCode, + nextPointId = agvEquip.objid, + nextPointNo = agvEquip.equipNo, + endPointId = wmsBaseLocation.locationId, + endPointNo = wmsBaseLocation.locationCode, + taskStatus = 0, + useFlag = 1, + containerNo = wmsProductStock.palletInfoCode, + createBy = "WCS", + createTime = DateTime.Now, + isEmpty = "0", + taskType = agvEquip.objid == 28 ? StaticTaskType.FiveRemove : StaticTaskType.SecondRemove, + qty = 1, + }; + fromLocationCode.locationStatus = "4"; + dbContext.Update(fromLocationCode); + wmsBaseLocation.locationStatus = "4"; + dbContext.Update(wmsBaseLocation); + dbContext.Add(wcsTask); + WcsTaskLog wcsTaskLog = CoreMapper.Map(wcsTask); + dbContext.Add(wcsTaskLog); + dbContext.SaveChanges(); + cannotIn.Clear(); + Console.WriteLine(DateTime.Now + ":二楼码垛输送线生成入库托盘任务成功:" + wcsTask.objid); + _logger.Info("二楼码垛输送线生成入库托盘任务成功:" + wcsTask.objid); + } + else + { + //报警 + } + } + } + } + } + } + + List wmsRawStocks = dbContext.WmsRawStock.Where(t => locationCodes.Contains(t.locationCode)).ToList(); + foreach (var wmsRawStock in wmsRawStocks) + { + + WmsBaseLocation fromLocationCode = CanRemoveWmsBaseLocations.First(t => t.locationCode == wmsRawStock.locationCode); + if (wmsRawStock.warehouseId == 511 || wmsRawStock.warehouseId == 311) + { + BaseEquip? agvEquip = null; + if (wmsRawStock.warehouseId == 511) + { + agvEquip = StaticData.BaseEquip.First(t => t.objid == 28); + } + else if (wmsRawStock.warehouseId == 311) + { + agvEquip = StaticData.BaseEquip.First(t => t.objid == 9); + } + if (agvEquip != null) + { + bool hasTask = dbContext.WcsTask.Where(t => t.nextPointId == agvEquip.objid).Any(); + if (!hasTask) + { + var wmsBaseLocations = dbContext.WmsBaseLocation + .Where(t => t.activeFlag == "1") + .Where(t => t.delFlag == "0") + .Where(t => t.locationScrapType == "1") + .Where(t => t.locationStatus == "1") + .Where(t => t.warehouseId == wmsRawStock.warehouseId) + .ToList();//所有可用库位 + var wmsProductStocks = dbContext.WmsRawStock + .Where(t => t.warehouseId == wmsRawStock.warehouseId) + .ToList();//仓库的库存 + WmsBaseLocation? wmsBaseLocation = null; + if (wmsBaseLocations.Count > 0) + { + List containerCodes = wmsBaseLocations + .Where(t => t.locDeep == 1) + .Select(t => t.containerCode).ToList();//深库位的有托盘 + + List mesBasePalletInfos = dbContext.MesBaseBarcodeInfo + .Where(t => t.saleOrderId == (wmsRawStock.saleOrderId == null ? 0 : wmsRawStock.saleOrderId))//销售订单 + .Where(t => t.materialId == wmsRawStock.materialId)//物料Id + .Where(t => containerCodes.Contains(t.palletInfoCode)).ToList();//深库位的托盘的物料等于当前任务的物料 + + var bill = from a in mesBasePalletInfos + join b in wmsBaseLocations.Where(t => t.locDeep == 1) on a.palletInfoCode equals b.containerCode + select new { b };//等于当前任务的物料的托盘的库位信息 + + var outBill = from a in bill//深库位托盘和当前任务绑定物料一致的托盘库位 + from b in wmsBaseLocations//所有库位 + where b.locDeep == 2//浅库位 + && b.locRow == (a.b.locRow % 2 == 0 ? a.b.locRow - 1 : a.b.locRow + 1) + //如果是4则找3,如果是1则找2 + && a.b.locColumn == b.locColumn//列数相同 + && string.IsNullOrEmpty(b.containerCode) + select new { a.b };//在上面的基础上获取对应托盘的外侧库位的空库位信息 + + wmsBaseLocation ??= outBill.FirstOrDefault()?.b;//先找相同物料的外侧库位 + wmsBaseLocation ??= wmsBaseLocations.Where(t => string.IsNullOrEmpty(t.containerCode)).FirstOrDefault(t => t.locDeep == 1);//找不到再找深库位 + wmsBaseLocation ??= wmsBaseLocations.Where(t => string.IsNullOrEmpty(t.containerCode)).FirstOrDefault();//找不到再找任意库位 + if (wmsBaseLocation != null)//如果找到库位,生成入库任务 + { + if (wmsBaseLocation.locDeep == 1) + { + bool hasLocation = wmsBaseLocations + .Where(t => t.locRow == (wmsBaseLocation.locRow % 2 == 1 ? (wmsBaseLocation.locRow + 1) : (wmsBaseLocation.locRow - 1))) + .Where(t => t.locColumn == wmsBaseLocation.locColumn) + .Any(); + if (!hasLocation) + { + Console.WriteLine(DateTime.Now + $":目标库位{wmsBaseLocation.locationCode}的浅库位库位状态异常,无法移库"); + _logger.Info($"目标库位{wmsBaseLocation.locationCode}的浅库位库位状态异常,无法移库"); + continue; + } + } + var wcsTask = new WcsTask() + { + objid = StaticData.SnowId.NextId(), + currPointId = fromLocationCode.locationId, + currPointNo = fromLocationCode.locationCode, + nextPointId = agvEquip.objid, + nextPointNo = agvEquip.equipNo, + endPointId = wmsBaseLocation.locationId, + endPointNo = wmsBaseLocation.locationCode, + taskStatus = 0, + useFlag = 1, + containerNo = wmsRawStock.palletInfoCode, + createBy = "WCS", + createTime = DateTime.Now, + isEmpty = "0", + taskType = agvEquip.objid == 28 ? StaticTaskType.FiveRemove : StaticTaskType.ThirdRemove, + qty = 1, + }; + fromLocationCode.locationStatus = "4"; + dbContext.Update(fromLocationCode); + wmsBaseLocation.locationStatus = "4"; + dbContext.Update(wmsBaseLocation); + dbContext.Add(wcsTask); + WcsTaskLog wcsTaskLog = CoreMapper.Map(wcsTask); + dbContext.Add(wcsTaskLog); + dbContext.SaveChanges(); + Console.WriteLine(DateTime.Now + ":二楼码垛输送线生成入库托盘任务成功:" + wcsTask.objid); + _logger.Info("二楼码垛输送线生成入库托盘任务成功:" + wcsTask.objid); + } + else + { + //报警 + } + } + } + } + } + } + } + catch + { + + } + } + } + + /// + /// 五楼柜体拆分返库任务 + /// + private void CreateRawInTaskLogic() + { + using var scope = _host.Services.CreateScope(); + using var dbContext = scope.ServiceProvider.GetRequiredService(); + List cannotIn = new List(); + while (true) + { + try + { + lock (SystemData.FiveTaskLock) + { + dbContext.ChangeTracker.Clear(); + BaseEquip baseEquip = dbContext.BaseEquip.First(t => t.objid == 29);//查出五楼柜体拆分验收区 + //if (baseEquip.emptyCount == 1) + { + WcsTask? wcsTask = dbContext.WcsTask.Where(t => t.nextPointId == 28).FirstOrDefault();//查询五楼AGV叉车是否有任务 + if (wcsTask == null)//AGV没有任务 + { + WmsRawInstock? wmsRawInstock = dbContext.WmsRawInstock.Where(t => t.warehouseId == 511 && (t.instockType == "2" || t.instockType == "4") && t.executeStatus == "0").FirstOrDefault();//查五楼有没有待执行的返库任务 + if (wmsRawInstock != null)//有入库任务 + { + MesBasePalletInfo? mesBasePalletInfo = dbContext.MesBasePalletInfo.FirstOrDefault(t => t.palletInfoCode == wmsRawInstock.palletInfoCode);//找到与入库任务的绑定托盘 + if (mesBasePalletInfo != null) + { + MesBaseBarcodeInfo? mesBaseBarcodeInfo = dbContext.MesBaseBarcodeInfo.FirstOrDefault(t => t.barcodeInfo == mesBasePalletInfo.materialBarcode);//找到与托盘信息中物料号对应的条码 + if (mesBaseBarcodeInfo != null) + { + var wmsBaseLocations = dbContext.WmsBaseLocation.Where(t => t.warehouseFloor == 5)//找一个可用的合适库位 + .Where(t => t.activeFlag == "1") + .Where(t => t.delFlag == "0") + .Where(t => t.locationScrapType == "1") + .Where(t => t.warehouseId == 511) + .Where(t => t.locationStatus == "1") + .OrderByDescending(t => t.locColumn) + .ToList(); + + List containerCodes = wmsBaseLocations + .Where(t => t.locDeep == 1) + .Select(t => t.containerCode).ToList();//深库位的托盘 + containerCodes.RemoveAll(t => string.IsNullOrEmpty(t)); + List mesBasePalletInfos = dbContext.MesBaseBarcodeInfo + .Where(t => t.materialId == mesBasePalletInfo.materialId) + .Where(t => t.saleOrderId == mesBaseBarcodeInfo.saleOrderId) + .Where(t => containerCodes.Contains(t.palletInfoCode)).ToList();//深库位的托盘的物料等于当前任务的物料 + + var bill = from a in mesBasePalletInfos + join b in wmsBaseLocations.Where(t => t.locDeep == 1 && t.returnFlag == "1") on a.palletInfoCode equals b.containerCode + select new { b };//等于当前任务的物料的托盘的库位信息 + + var outBill = from a in bill + from b in wmsBaseLocations + where b.locDeep == 2 + && b.locRow == (a.b.locRow % 2 == 0 ? a.b.locRow - 1 : a.b.locRow + 1) + && a.b.locColumn == b.locColumn + && b.locationStatus == "1" + && string.IsNullOrEmpty(b.containerCode) + select new { a, b };//在上面的基础上获取对应托盘的外侧库位的空库位信息 + + WmsBaseLocation? wmsBaseLocation = null; + wmsBaseLocation ??= outBill.Where(t => !cannotIn.Contains(t.b.locationCode)).FirstOrDefault()?.b;//先找相同物料的外侧库位 + wmsBaseLocation ??= wmsBaseLocations.Where(t => !cannotIn.Contains(t.locationCode)).Where(t => string.IsNullOrEmpty(t.containerCode)).FirstOrDefault(t => t.locDeep == 1);//找不到再找深库位 + wmsBaseLocation ??= wmsBaseLocations.Where(t => !cannotIn.Contains(t.locationCode)).Where(t => string.IsNullOrEmpty(t.containerCode)).FirstOrDefault();//找不到再找任意库位 + //深浅库位问题?库位入库优先级等 + + var AgvEquip = StaticData.BaseEquip.First(t => t.objid == 28);//5楼叉车 + if (wmsBaseLocation != null)//找到的库位 + { + if (wmsBaseLocation.locDeep == 1)//入浅库位 + { + bool hasLocation = wmsBaseLocations + .Where(t => t.locRow == (wmsBaseLocation.locRow % 2 == 1 ? (wmsBaseLocation.locRow + 1) : (wmsBaseLocation.locRow - 1))) + .Where(t => t.locColumn == wmsBaseLocation.locColumn).Any(); + if (!hasLocation) + { + cannotIn.Add(wmsBaseLocation.locationCode); + Console.WriteLine(DateTime.Now + $":目标库位{cannotIn.Join(",")}的浅库位库位状态异常,无法入库"); + _logger.Info($"目标库位{cannotIn.Join(",")}的浅库位库位状态异常,无法入库"); + continue; + } + } + WcsTask newTask = new WcsTask();//创建任务 + newTask.taskStatus = 0;//创建状态 + newTask.updateTime = DateTime.Now; + newTask.currPointId = baseEquip.objid; + newTask.currPointNo = baseEquip.equipNo; + newTask.nextPointId = AgvEquip.objid; + newTask.nextPointNo = AgvEquip.equipNo; + newTask.endPointId = wmsBaseLocation.locationId; + newTask.endPointNo = wmsBaseLocation.locationCode; + newTask.containerNo = mesBasePalletInfo.palletInfoCode; + newTask.materialId = mesBasePalletInfo.materialId; + newTask.objid = StaticData.SnowId.NextId(); + newTask.createTime = DateTime.Now; + newTask.taskType = StaticTaskType.FiveRawSplitReturn; + newTask.useFlag = 1; + wmsBaseLocation.locationStatus = "2"; + WmsRawInstockDetail wmsRawInstockDetail = new WmsRawInstockDetail + { + rawInstockDetailId = StaticData.SnowId.NextId(), + stackAmount = 1, + erpStatus = "0", + executeStatus = "1", + qualityStatus = "0", + activeFlag = "1", + createBy = "WCS", + createDate = DateTime.Now, + erpAmount = 0, + instockAmount = 1, + instockBatch = mesBasePalletInfo.materialBarcode, + instockTime = DateTime.Now, + instockWay = "2", + locationCode = newTask.endPointNo, + machineName = mesBaseBarcodeInfo.machineName, + materialBarcode = mesBasePalletInfo.materialBarcode, + materialId = mesBaseBarcodeInfo.materialId, + materialProductionDate = mesBaseBarcodeInfo.productionDate, + planAmount = 1, + poNo = mesBaseBarcodeInfo.poNo, + rawInstockId = wmsRawInstock.rawInstockId, + taskCode = wmsRawInstock.taskCode, + }; + SystemData.LockOutLocation(wmsBaseLocation, dbContext); + dbContext.Add(wmsRawInstockDetail); + dbContext.Update(wmsBaseLocation); + dbContext.Add(newTask); + WcsTaskLog wcsTaskLog = CoreMapper.Map(newTask); + dbContext.Add(wcsTaskLog); + dbContext.SaveChanges(); + cannotIn.Clear(); + } + } + } + } + } + } + } + } + catch (Exception ex) + { + _logger.Error(ex.Message + "\n" + ex.StackTrace); + } + Thread.Sleep(5000); + } + } + + /// + /// 根据人工任务生成可执行任务 + /// + /// + private void CreateThirdWasterTaskLogic() + { + using var scope = _host.Services.CreateScope(); + using var dbContext = scope.ServiceProvider.GetRequiredService(); + while (true) + { + try + { + dbContext.ChangeTracker.Clear(); + bool hasTask = dbContext.WcsTask.Where(t => t.nextPointId == 9).Where(t => t.useFlag == 1).Any(); + if (!hasTask) + { + WcsTaskManual? wcsTaskManual = dbContext.WcsTaskManual.Where(t => t.nextPointId == 9 || t.nextPointId == 8).OrderBy(t => t.createBy).FirstOrDefault(); + if (wcsTaskManual != null) + { + var equip = dbContext.BaseEquip.Where(t => t.objid == wcsTaskManual.endPointId).FirstOrDefault(); + if (equip != null && equip.equipStatus == 0) + { + WcsTask wcsTask = CoreMapper.Map(wcsTaskManual); + wcsTask.createTime = DateTime.Now; + WcsTaskLog wcsTaskLog = CoreMapper.Map(wcsTask); + dbContext.Add(wcsTask); + dbContext.Add(wcsTaskLog); + dbContext.Remove(wcsTaskManual); + dbContext.SaveChanges(); + } + } + } + } + catch (Exception ex) + { + _logger.Error(ex.Message + "\n" + ex.StackTrace); + } + Thread.Sleep(5000); + } + } + + /// + /// 3楼托盘库出库任务 + /// + /// + private void CreateEmptyTrayLogic() + { + using var scope = _host.Services.CreateScope(); + using var dbContext = scope.ServiceProvider.GetRequiredService(); + BaseEquip agvEquip = StaticData.BaseEquip.First(t => t.objid == 9); + while (true) + { + try + { + dbContext.ChangeTracker.Clear(); + bool canCreate = dbContext.WcsTask.Where(t => t.nextPointId == 9) + .Where(t => t.useFlag == 1) + .Where(t => t.taskStatus <= 6).Any(); + if (!canCreate) + { + BaseEquip baseEquip = dbContext.BaseEquip.First(t => t.objid == 35); + #region 原逻辑 + if (baseEquip.emptyCount == (SystemData.maxTray / 2)) + { + var endEquip = dbContext.BaseEquip.FirstOrDefault(t => t.equipType == 15 && t.equipStatus == 1 && t.emptyCount == (SystemData.maxTray / 2)); + if (endEquip != null) + { + var wcsTask = new WcsTask() + { + objid = StaticData.SnowId.NextId(), + serialNo = SystemData.GetSerialNo(dbContext), + taskType = 40, + nextPointId = agvEquip.objid, + nextPointNo = agvEquip.equipNo, + endPointId = baseEquip.objid, + endPointNo = baseEquip.equipNo, + currPointId = endEquip.objid, + currPointNo = endEquip.equipNo, + equipmentNo = agvEquip.equipNo, + useFlag = 1, + qty = 5, + isEmpty = "1", + taskStatus = 0, + createBy = "WCS", + createTime = DateTime.Now, + floorNo = 3, + fromFloorNo = 3, + masterId = 0, + orderId = 0, + materialId = 0, + }; + WcsTaskLog wcsTaskLog = CoreMapper.Map(wcsTask); + dbContext.Add(wcsTask); + dbContext.Add(wcsTaskLog); + dbContext.SaveChanges(); + } + else + { + endEquip = dbContext.BaseEquip.FirstOrDefault(t => t.equipType == 15 && t.equipStatus == 0 && t.emptyCount == 0); + if (endEquip != null) + { + var wcsTask = new WcsTask() + { + objid = StaticData.SnowId.NextId(), + serialNo = SystemData.GetSerialNo(dbContext), + taskType = 43, + nextPointId = agvEquip.objid, + nextPointNo = agvEquip.equipNo, + endPointId = endEquip.objid, + endPointNo = endEquip.equipNo, + currPointId = baseEquip.objid, + currPointNo = baseEquip.equipNo, + equipmentNo = agvEquip.equipNo, + useFlag = 1, + qty = 5, + isEmpty = "1", + taskStatus = 0, + createBy = "WCS", + createTime = DateTime.Now, + floorNo = 3, + fromFloorNo = 3, + masterId = 0, + orderId = 0, + materialId = 0, + }; + WcsTaskLog wcsTaskLog = CoreMapper.Map(wcsTask); + dbContext.Add(wcsTask); + dbContext.Add(wcsTaskLog); + dbContext.SaveChanges(); + } + } + } + else + #endregion + if (baseEquip.emptyCount == SystemData.maxTray)//达到最大值 + { + var endEquip = dbContext.BaseEquip.FirstOrDefault(t => t.equipType == 15 && t.equipStatus == 0 && t.emptyCount == 0);//找周转区 + if (endEquip != null) + { + var wcsTask = new WcsTask() + { + objid = StaticData.SnowId.NextId(), + serialNo = SystemData.GetSerialNo(dbContext), + taskType = StaticTaskType.ThirdBinToTransit, + nextPointId = agvEquip.objid, + nextPointNo = agvEquip.equipNo, + endPointId = endEquip.objid, + endPointNo = endEquip.equipNo, + currPointId = baseEquip.objid, + currPointNo = baseEquip.equipNo, + equipmentNo = agvEquip.equipNo, + useFlag = 1, + qty = SystemData.maxTray, + isEmpty = "1", + taskStatus = 0, + createBy = "WCS", + createTime = DateTime.Now, + floorNo = 3, + fromFloorNo = 3, + masterId = 0, + orderId = 0, + materialId = 0, + }; + WcsTaskLog wcsTaskLog = CoreMapper.Map(wcsTask); + dbContext.Add(wcsTask); + dbContext.Add(wcsTaskLog); + dbContext.SaveChanges(); + } + } + } + } + catch (Exception ex) + { + _logger.Error(ex.Message + "\n" + ex.StackTrace); + } + Thread.Sleep(5000); + } + } + + /// + /// 背负式Agv退库 + /// + private void BackReturnTaskLogic() + { + using var scope = _host.Services.CreateScope(); + using var dbContext = scope.ServiceProvider.GetRequiredService(); + while (true) + { + try + { + dbContext.ChangeTracker.Clear(); + BaseEquip baseEquip = dbContext.BaseEquip.First(t => t.objid == 10); + if (baseEquip.IsOut == 2 && !string.IsNullOrEmpty(baseEquip.endStationCode)) + { + bool hasTask = dbContext.WcsTask.Where(t => t.nextPointId == 10).Any(); + if (!hasTask) + { + string endStationCode = baseEquip.endStationCode; + try + { + List? list = JsonConvert.DeserializeObject>(baseEquip.endStationCode); + if (list != null && list.Count > 0) + { + endStationCode = list[0]; + } + } + catch + { + + } + BaseEquip startEquip = StaticData.BaseEquip.First(t => t.equipNo == endStationCode); + List wmsRawReturns = dbContext.WmsRawReturn.Where(t => t.endStationCode == endStationCode) + .Where(t => t.auditStatus == "1") + .Where(t => t.executeStatus == "0" || t.executeStatus == "1") + .ToList(); + wmsRawReturns.ForEach(t => t.executeStatus = "1"); + dbContext.UpdateRange(wmsRawReturns); + BaseEquip endEquip = StaticData.BaseEquip.First(t => t.objid == 21); + var wcsTask = new WcsTask() + { + objid = StaticData.SnowId.NextId(), + serialNo = SystemData.GetSerialNo(dbContext), + taskType = 48, + nextPointId = baseEquip.objid, + nextPointNo = baseEquip.equipNo, + currPointId = startEquip.objid, + currPointNo = startEquip.equipNo, + endPointId = endEquip.objid, + endPointNo = endEquip.equipNo, + equipmentNo = baseEquip.equipNo, + useFlag = 1, + qty = 1, + taskStatus = 0, + containerNo = "", + IsDelete = 0, + createTime = DateTime.Now, + }; + baseEquip.IsOut = 0; + dbContext.Update(baseEquip); + WcsTaskLog wcsTaskLog = CoreMapper.Map(wcsTask); + dbContext.Add(wcsTask); + dbContext.Add(wcsTaskLog); + dbContext.SaveChanges(); + } + } + } + catch (Exception ex) + { + _logger.Error(ex.Message + "\n" + ex.StackTrace); + } + Thread.Sleep(5000); + } + } + + /// + /// 半成品入库 + /// + /// + private void CreateFiveProductInTaskLogic() + { + using var scope = _host.Services.CreateScope(); + using var dbContext = scope.ServiceProvider.GetRequiredService(); + BaseEquip agvEquip = StaticData.BaseEquip.First(t => t.objid == 28); + BaseEquip endEquip = StaticData.BaseEquip.First(t => t.objid == 30); + while (true) + { + try + { + dbContext.ChangeTracker.Clear(); + bool task = dbContext.WcsTask.Where(t => t.nextPointId == 28 && t.useFlag == 1 && t.taskStatus <= 5).Any(); + if (!task) + { + var wmsProductInstock = dbContext.WmsProductInstock + .Where(t => t.productType == "2") + .Where(t => t.auditStatus == "1" && t.executeStatus == "0") + .Where(t => t.warehouseId == 521) + .FirstOrDefault(); + if (wmsProductInstock != null) + { + var wmsBaseLocation = dbContext.WmsBaseLocation + .Where(t => t.activeFlag == "1") + .Where(t => t.delFlag == "0") + .Where(t => t.locationScrapType == "1") + .Where(t => t.locationStatus == "1") + .Where(t => string.IsNullOrEmpty(t.containerCode)) + .Where(t => t.warehouseId == 521) + .OrderByDescending(t => t.locColumn) + .FirstOrDefault(); + if (wmsBaseLocation != null) + { + var wcsTask = new WcsTask() + { + objid = StaticData.SnowId.NextId(), + serialNo = SystemData.GetSerialNo(dbContext), + taskType = StaticTaskType.FiveHalfIn, + endPointId = wmsBaseLocation.locationId, + endPointNo = wmsBaseLocation.locationCode, + currPointId = endEquip.objid, + currPointNo = endEquip.equipNo, + equipmentNo = agvEquip.equipNo, + useFlag = 1, + qty = 1, + containerNo = wmsProductInstock.palletInfoCode, + taskStatus = 0, + createBy = "WCS", + createTime = DateTime.Now, + floorNo = 5, + fromFloorNo = 5, + isEmpty = "0", + masterId = wmsProductInstock.productId, + orderId = wmsProductInstock.productInstockId, + materialId = wmsProductInstock.productId, + nextPointId = agvEquip.objid, + nextPointNo = agvEquip.equipNo, + materialBarcode = wmsProductInstock.productBatch, + }; + //WmsProductInstockDetail wmsProductInstockDetail = new WmsProductInstockDetail() + //{ + // erpAmount = 0, + // productId = wmsProductInstock.productId, + // executeStatus = "1", + // productInstockDetailId = StaticData.SnowId.NextId(), + // instockAmount = 1, + // instockBy = "WCS", + // instockDate = DateTime.Now, + // instockWay = "2", + // locationCode = wmsBaseLocation.locationCode, + // planAmount = 1, + // productBarcode = wmsProductInstock.productBatch, + // productBatch = wmsProductInstock.productBatch, + // productInstockId = wmsProductInstock.productInstockId, + //}; + WcsTaskLog wcsTaskLog = CoreMapper.Map(wcsTask); + wmsProductInstock.executeStatus = "1"; + wmsBaseLocation.locationStatus = "2"; + //dbContext.Add(wmsProductInstockDetail); + dbContext.Update(wmsProductInstock); + dbContext.Update(wmsBaseLocation); + dbContext.Add(wcsTask); + dbContext.Add(wcsTaskLog); + dbContext.SaveChanges(); + } + else + { + //报警 + } + } + } + } + catch (Exception ex) + { + _logger.Error(ex.Message + "\n" + ex.StackTrace); + } + Thread.Sleep(5000); + } + } + + /// + /// 创建去翻转机的任务 + /// + /// + /// + private void CreateThirdOutTaskLogic() + { + BaseEquip endEquip = StaticData.BaseEquip.First(t => t.objid == 31); + BaseEquip baseEquip = StaticData.BaseEquip.First(t => t.objid == 9); + using var scope = _host.Services.CreateScope(); + using var dbContext = scope.ServiceProvider.GetRequiredService(); + while (true) + { + try + { + lock (SystemData.ThirdTaskLock) + { + dbContext.ChangeTracker.Clear(); + bool task = dbContext.WcsTask.Where(t => t.nextPointId == 9 && t.taskStatus <= 5).Any(); + if (!task) + { + endEquip = dbContext.BaseEquip.First(t => t.objid == 31); + if (endEquip.emptyCount == 0) + { + WcsTask? wcsTask = dbContext.WcsTask.FirstOrDefault(t => t.endPointId == endEquip.objid); + if (wcsTask == null) + { + WcsTaskManual? wcsTaskManual = dbContext.WcsTaskManual.Where(t => t.taskType == 999).FirstOrDefault();//调接口生成的任务 + + if (wcsTaskManual != null) + { + + var wmsRawOutstock = dbContext.WmsRawOutstock.FirstOrDefault(t => t.rawOutstockId == wcsTaskManual.orderId); + if (!string.IsNullOrEmpty(wcsTaskManual.startPointNo)) //手动投料没有申请单 + { + wmsRawOutstock = null; + } + var wmsRawStocks = dbContext.WmsRawStock + .WhereIf(wmsRawOutstock != null, t => t.saleOrderId == (wmsRawOutstock.saleOrderId == null ? 0 : wmsRawOutstock.saleOrderId)) + .WhereIf(wmsRawOutstock != null, t => t.materialId == wmsRawOutstock.materialId) + .Where(t => t.warehouseId == 311) + .Where(t => t.totalAmount > t.frozenAmount) + .ToList(); + var wmsRawStockLocations = wmsRawStocks.Select(x => x.locationCode).ToList(); + var AllWmsBaseLocations = dbContext.WmsBaseLocation + .Where(t => t.activeFlag == "1") + .Where(t => t.delFlag == "0") + .Where(t => t.locationScrapType == "1") + .Where(t => t.warehouseId == 311) + .Where(t => t.locationStatus == "1").ToList(); + + var wmsBaseLocations = AllWmsBaseLocations + .Where(t => t.warehouseId == 311) + .Where(t => wmsRawStockLocations.Contains(t.locationCode)) + .WhereIf(!string.IsNullOrEmpty(wcsTaskManual.startPointNo), t => t.locationCode == wcsTaskManual.startPointNo) + .ToList(); + + //手动模式 + if (!string.IsNullOrEmpty(wcsTaskManual.startPointNo)) + { + wmsBaseLocations = dbContext.WmsBaseLocation.Where(x => x.locationCode == wcsTaskManual.startPointNo).ToList(); + + var wmsRawPreferredOut = dbContext.WmsRawPreferredOut.Where(t => t.LocationCode == wcsTaskManual.startPointNo).FirstOrDefault(); + if (wmsRawPreferredOut != null) + { + dbContext.Remove(wmsRawPreferredOut); + } + } + var bill = from a in wmsBaseLocations + from b in wmsRawStocks + where a.locationCode == b.locationCode + select new { a, b }; + WmsBaseLocation? wmsBaseLocation = null; + WmsRawStock? wmsRawStock = null; + var inLocations = AllWmsBaseLocations.Where(t => t.locDeep == 1).Where(t => !string.IsNullOrEmpty(t.containerCode)).ToList(); + var outLocations = AllWmsBaseLocations.Where(t => t.locDeep == 2).Where(t => string.IsNullOrEmpty(t.containerCode)).ToList(); + var list = new List(); + foreach (var item in inLocations) + { + if (outLocations.Where(t => t.locRow == (item.locRow % 2 == 0 ? item.locRow - 1 : item.locRow + 1)) + .Where(t => t.locColumn == item.locColumn).Any()) + { + list.Add(item.locationCode); + } + } + bill = bill.OrderBy(t => list.Contains(t.a.locationCode) ? 0 : 1).OrderBy(t => t.b.instockDate.Value.Date);//按某个时间段 + //#endregion + + foreach (var item in bill) + { + // 目标库位 + var fistbill = item; + + int? locRow = 0; + if (fistbill.a.locRow % 2 == 1) + { + locRow = fistbill.a.locRow + 1; + } + else + { + locRow = fistbill.a.locRow - 1; + } + wmsBaseLocation = fistbill.a; + + // 目标库位处于深库位,判断是否需要移库浅库位 + if (wmsBaseLocation.locDeep == 1) + { + int? row = 0; + if (wmsBaseLocation.locRow % 2 == 1) + { + row = wmsBaseLocation.locRow + 1; + } + else + { + row = wmsBaseLocation.locRow - 1; + } + + var lowLocationBill = bill.Where(t => t.a.locRow == locRow).Where(t => t.a.locColumn == wmsBaseLocation.locColumn).Where(t => t.a.warehouseId == wmsBaseLocation.warehouseId).FirstOrDefault(); + if (lowLocationBill != null) + { + //对应的浅库位满足条件,直接出浅库位 + wmsBaseLocation = lowLocationBill.a; + } + else + { + //目标出库库位对应的浅库位 + WmsBaseLocation? fromBaseLocation = dbContext.WmsBaseLocation.Where(t => t.locRow == row) + .Where(t => t.locColumn == wmsBaseLocation.locColumn) + .Where(t => t.warehouseId == wmsBaseLocation.warehouseId).FirstOrDefault(); + if (fromBaseLocation != null && !string.IsNullOrEmpty(fromBaseLocation.containerCode) && fromBaseLocation.locationStatus == "1") + { + // 浅库位有库存 + WmsRawStock? wmsRawStock1 = dbContext.WmsRawStock.FirstOrDefault(t => t.locationCode == fromBaseLocation.locationCode); + if (wmsRawStock1 != null) + { + #region 找寻移库目标库位 + // 寻找移库目的库位 + WmsBaseLocation? toLocation = null; + + var moveLocationList = AllWmsBaseLocations.Where(t => t.warehouseId == fromBaseLocation.warehouseId) + .Where(t => t.locationId != fromBaseLocation.locationId) + .Where(t => string.IsNullOrEmpty(t.containerCode)).OrderBy(t => t.locDeep).ToList(); + + foreach (WmsBaseLocation itemLocation in moveLocationList) + { + + if (itemLocation.locDeep == 1) + { + bool hasLocation = AllWmsBaseLocations + .Where(t => t.locRow == (itemLocation.locRow % 2 == 1 ? (itemLocation.locRow + 1) : (itemLocation.locRow - 1))) + .Where(t => t.locColumn == itemLocation.locColumn) + .Where(t => t.locationStatus == "1" && string.IsNullOrEmpty(t.containerCode)) + .Any(); + if (!hasLocation) + { + Console.WriteLine(DateTime.Now + $":目标库位的浅库位库位状态异常,无法移库"); + _logger.Info($"目标库位的浅库位库位状态异常,无法移库"); + continue; + } + else + { + // 找到可以移库的目标库位 + toLocation = itemLocation; + break; + } + + } + else + { + // 找到可以移库的目标库位 + toLocation = itemLocation; + break; + } + + } + if (toLocation == null) + { + // 找寻下一个可出库库存 + continue; + } + + var RemoveTask = new WcsTask() + { + objid = StaticData.SnowId.NextId(), + taskType = StaticTaskType.ThirdRemove, + containerNo = wmsRawStock1.palletInfoCode, + createBy = "WCS", + createTime = DateTime.Now.AddSeconds(-10), + taskStatus = 0, + currPointId = fromBaseLocation.locationId, + currPointNo = fromBaseLocation.locationCode, + nextPointId = baseEquip.objid, + nextPointNo = baseEquip.equipNo, + endPointId = toLocation.locationId, + endPointNo = toLocation.locationCode, + equipmentNo = baseEquip.equipNo, + useFlag = 1, + qty = 1 + }; + SystemData.LockOutLocation(toLocation, dbContext); + SystemData.LockOutLocation(fromBaseLocation, dbContext); + toLocation.locationStatus = "4"; + toLocation.updateBy = "WCS"; + toLocation.updateTime = DateTime.Now; + fromBaseLocation.updateBy = "WCS"; + fromBaseLocation.updateTime = DateTime.Now; + fromBaseLocation.locationStatus = "4"; + dbContext.Update(toLocation); + dbContext.Update(fromBaseLocation); + dbContext.Add(RemoveTask); + WcsTaskLog wcsTaskLog = CoreMapper.Map(RemoveTask); + dbContext.Add(wcsTaskLog); + #endregion + } + } + else if (fromBaseLocation != null && fromBaseLocation.locationStatus != "1") + { + //浅库位状态异常,找寻下一个可出库库存 + continue; + } + else if (fromBaseLocation == null)//浅库位无信息 + { + continue; + } + } + } + + if (wmsBaseLocation != null) + { + wmsRawStock = wmsRawStocks.Where(t => t.locationCode == wmsBaseLocation.locationCode).First(); + MesBasePalletInfo? mesBasePalletInfo = dbContext.MesBasePalletInfo.FirstOrDefault(t => t.palletInfoCode == wmsRawStock.palletInfoCode); + if (mesBasePalletInfo != null) + { + MesBaseBarcodeInfo? mesBaseBarcodeInfo = dbContext.MesBaseBarcodeInfo.FirstOrDefault(t => t.barcodeInfo == mesBasePalletInfo.materialBarcode); + if (mesBaseBarcodeInfo != null) + { + + if (wmsRawOutstock == null) + { + wmsRawOutstock = new WmsRawOutstock(); + + wmsRawOutstock.rawOutstockId = StaticData.SnowId.NextId(); + wmsRawOutstock.taskCode = StaticData.SnowId.NextId().ToString(); + wmsRawOutstock.warehouseId = 311; + wmsRawOutstock.locationCode = wmsBaseLocation.locationCode; + wmsRawOutstock.materialId = mesBaseBarcodeInfo.materialId; + wmsRawOutstock.materialBatch = mesBaseBarcodeInfo.barcodeInfo; + wmsRawOutstock.palletInfoCode = wmsBaseLocation.containerCode; + wmsRawOutstock.outstockAmount = 1; + wmsRawOutstock.realOutstockAmount = 0; + wmsRawOutstock.operationType = "1"; + wmsRawOutstock.taskType = "1"; + wmsRawOutstock.auditStatus = "1"; + wmsRawOutstock.executeStatus = "0"; + wmsRawOutstock.applyBy = "WCS"; + wmsRawOutstock.auditDate = DateTime.Now; + wmsRawOutstock.saleOrderId = mesBaseBarcodeInfo != null ? mesBaseBarcodeInfo.saleOrderId : 0; + dbContext.Add(wmsRawOutstock); + } + //if (wmsRawOutstock != null) + //{ + // WmsRawOutstockDetail wmsRawOutstockDetail = new WmsRawOutstockDetail() + // { + // rawOutstockDetailId = StaticData.SnowId.NextId(), + // createBy = "WCS", + // createDate = DateTime.Now, + // executeStatus = "0", + // erpAmount = 0, + // erpStatus = "0", + // instockBatch = mesBaseBarcodeInfo.batchCode, + // stackAmount = 1, + // locationCode = wmsBaseLocation.locationCode, + // rawOutstockId = wmsRawOutstock.rawOutstockId, + // planAmount = 1, + // outstockWay = "2", + // outstockPerson = "WCS", + // outstockTime = DateTime.Now, + // materialProductionDate = mesBaseBarcodeInfo.productionDate, + // materialBarcode = mesBasePalletInfo.materialBarcode, + // materialId = wmsRawOutstock.materialId, + // machineName = mesBaseBarcodeInfo.machineName, + // outstockAmount = 1, + // taskCode = wmsRawOutstock.taskCode + // }; + // dbContext.Add(wmsRawOutstockDetail); + //} + wcsTask = new WcsTask() + { + objid = StaticData.SnowId.NextId(), + orderId = wmsRawOutstock?.rawOutstockId, + taskType = StaticTaskType.ThirdRawToFlip, + containerNo = wmsRawStock.palletInfoCode, + createBy = "WCS", + createTime = DateTime.Now, + taskStatus = 0, + materialId = mesBaseBarcodeInfo.materialId, + currPointId = wmsBaseLocation.locationId, + currPointNo = wmsBaseLocation.locationCode, + nextPointId = baseEquip.objid, + nextPointNo = baseEquip.equipNo, + endPointId = endEquip.objid, + endPointNo = endEquip.equipNo, + equipmentNo = endEquip.equipNo, + useFlag = 1, + qty = 1 + }; + + SystemData.LockOutLocation(wmsBaseLocation, dbContext); + wmsBaseLocation.locationStatus = "6"; + dbContext.Update(wmsBaseLocation); + WcsTaskLog wcsTaskLog = CoreMapper.Map(wcsTask); + dbContext.Remove(wcsTaskManual); + dbContext.Add(wcsTask); + dbContext.Add(wcsTaskLog); + dbContext.SaveChanges(); + break; + } + } + } + + } + } + } + } + } + } + } + catch (Exception ex) + { + _logger.Error(ex.Message + "\n" + ex.StackTrace); + } + finally + { + Thread.Sleep(5000); + } + } + } + + /// + /// 创建返库任务 + /// + /// + private void CreateBearAgvReturnLogic() + { + using var scope = _host.Services.CreateScope(); + using var dbContext = scope.ServiceProvider.GetRequiredService(); + BaseEquip endEquip = StaticData.BaseEquip.First(t => t.objid == 21); + while (true) + { + try + { + dbContext.ChangeTracker.Clear(); + BaseEquip baseEquip = dbContext.BaseEquip.First(t => t.objid == 10); + + if (!string.IsNullOrEmpty(baseEquip.endStationCode) && baseEquip.ud3 == "1") + { + string endStationCode = baseEquip.endStationCode; + try + { + endStationCode = JsonConvert.DeserializeObject>(endStationCode)[0]; + } + catch + { + + } + var wmsRawReturn = dbContext.WmsRawReturn + .Where(t => t.auditStatus == "1") + .Where(t => t.executeStatus == "0") + .Where(t => t.endStationCode == baseEquip.endStationCode) + .FirstOrDefault(); + if (wmsRawReturn != null) + { + bool hasTask = dbContext.WcsTask.Where(t => t.nextPointId == baseEquip.objid).Any(); + if (!hasTask) + { + //任务未开始Status=0 + BaseEquip? startEquip = StaticData.BaseEquip.FirstOrDefault(t => t.equipNo == wmsRawReturn.endStationCode); + if (startEquip != null) + { + WcsTask wcsTask = new() + { + objid = StaticData.SnowId.NextId(), + orderId = wmsRawReturn.rawReturnId, + taskType = 48, + containerNo = null, + currPointId = startEquip.objid, + currPointNo = startEquip.equipNo, + nextPointId = baseEquip.objid, + nextPointNo = baseEquip.equipNo, + endPointId = endEquip.objid, + endPointNo = endEquip.equipNo, + serialNo = SystemData.GetSerialNo(dbContext), + taskStatus = 0, + createTime = DateTime.Now, + createBy = "WCS", + materialId = wmsRawReturn.materialId, + qty = 1, + useFlag = 1, + equipmentNo = startEquip.equipNo, + remark = "装配区返库", + floorNo = 5, + masterId = wmsRawReturn.materialId, + fromFloorNo = 5, + //materialNo = wmsRawReturn.materialBatch, + }; + baseEquip.ud3 = null; + dbContext.Update(baseEquip); + dbContext.Add(wcsTask); + WcsTaskLog wcsTaskLog = CoreMapper.Map(wcsTask); + dbContext.Add(wcsTaskLog); + dbContext.Update(wmsRawReturn); + dbContext.SaveChanges(); + } + } + } + } + } + catch (Exception ex) + { + _logger.Error(ex.Message + "\n" + ex.StackTrace); + } + Thread.Sleep(5000); + } + } + + + #region 2楼、3楼指定库位成品出库 + /// + /// 人工指定库位成品出库 + /// 二楼、五楼指定库位成品出库任务 + /// + private void CreateProductTaskByLocationCodeLogic() + { + using var scope = _host.Services.CreateScope(); + using var dbContext = scope.ServiceProvider.GetRequiredService(); + while (true) + { + try + { + dbContext.ChangeTracker.Clear(); + + bool fiveTask = dbContext.WcsTask.Where(t => t.nextPointId == 28 && t.taskStatus <= 5).Any(); + if (!fiveTask) + { + var fiveProOutStock = dbContext.WmsProductOutstock + .Where(t => t.outstockQty < t.applyQty) + .Where(t => t.auditStatus == "1") + .Where(t => t.warehouseId == 531) + .Where(t => t.operationType == "1") //不指定库位0,指定库位1 + .Where(t => t.productType == "3") + .Where(t => t.executeStatus == "0" || t.executeStatus == "1").FirstOrDefault(); + //创建任务 + if (fiveProOutStock != null) + { + CreateTask(fiveProOutStock); + } + } + bool twoTask = dbContext.WcsTask.Where(t => t.nextPointId == 8 && t.taskStatus <= 7).Any(); + if (!twoTask) + { + var twoProOutStock = dbContext.WmsProductOutstock + .Where(t => t.outstockQty < t.applyQty) + .Where(t => t.auditStatus == "1") + .Where(t => t.warehouseId == 231) + .Where(t => t.operationType == "1") //不指定库位0,指定库位1 + .Where(t => t.productType == "3") + .Where(t => t.executeStatus == "0" || t.executeStatus == "1").FirstOrDefault(); + + //创建任务 + if (twoProOutStock != null) + { + CreateTask(twoProOutStock); + } + } + + + } + catch (Exception ex) + { + Console.WriteLine(ex.Message + ex.StackTrace); + _logger.Error(ex.Message + "\n" + ex.StackTrace); + } + Thread.Sleep(5000); + } + } + + /// + /// 二楼、五楼指定库位根据申请单成品出库任务 + /// + /// + private void CreateTask(WmsProductOutstock wmsProductOutstock) + { + try + { + using var scope = _host.Services.CreateScope(); + using var dbContext = scope.ServiceProvider.GetRequiredService(); + + BaseEquip agvEquip = StaticData.BaseEquip.First(t => t.objid == (wmsProductOutstock.warehouseId == 531 ? 28 : 8)); + + BaseEquip endEquip = StaticData.BaseEquip.First(t => t.objid == (wmsProductOutstock.warehouseId == 531 ? 5 : 1)); + List AllWmsBaseLocations = dbContext.WmsBaseLocation.Where(t => t.warehouseId == wmsProductOutstock.warehouseId).ToList(); + List details = dbContext.WmsProductOutstockDetail.Where(t => t.productOutstockId == wmsProductOutstock.productOutstockId).ToList(); + if (details.Count == 0) return; + var locationCodes = details.Select(t => t.locationCode).Distinct().ToList(); + //待出库列表 + List baseLocations = AllWmsBaseLocations.Where(t => locationCodes.Contains(t.locationCode) && t.warehouseId == wmsProductOutstock.warehouseId).ToList(); + + baseLocations = baseLocations.OrderByDescending(t => t.locDeep).ToList(); // 浅库位优先 + //目标出库库位 + WmsBaseLocation targetLocation = null; + foreach (var item in baseLocations) + { + //二次校验任务 + bool hasTask = false; + if (wmsProductOutstock.warehouseId == 531) + { + hasTask = dbContext.WcsTask.Where(t => t.nextPointId == 28 && t.taskStatus <= 5).Any(); + } + else + { + hasTask = dbContext.WcsTask.Where(t => t.nextPointId == 8 && t.taskStatus <= 7).Any(); + } + if (hasTask) + { + continue; + } + + if (item.locDeep == 2 && item.locationStatus == "1" && !string.IsNullOrEmpty(item.containerCode)) + { // 浅库位满足条件直接出 + targetLocation = item; + break; + } + if (item.locDeep == 1 && item.locationStatus == "1" && !string.IsNullOrEmpty(item.containerCode)) //深库位出库 ,若浅库位有东西需要移库 + { + // 计算对应浅库位坐标 + int? locRow = item.locRow % 2 == 0 ? item.locRow - 1 : item.locRow + 1; + // 外侧浅库位 + WmsBaseLocation? wmsBaseLocation = AllWmsBaseLocations.Where(t => t.locRow == locRow) + .Where(t => t.locColumn == item.locColumn) + .Where(t => t.warehouseId == item.warehouseId).FirstOrDefault(); + if (wmsBaseLocation.locationStatus == "1" && !string.IsNullOrEmpty(wmsBaseLocation.containerCode)) + { //移库 + + #region 找寻移库目标库位 + + WmsBaseLocation? toLocation = null; + + var moveLocationList = AllWmsBaseLocations.Where(t => t.warehouseId == item.warehouseId) + .Where(t => string.IsNullOrEmpty(t.containerCode) && t.locationStatus == "1").OrderBy(t => t.locDeep).ToList(); + + foreach (WmsBaseLocation itemLocation in moveLocationList) + { + + if (itemLocation.locDeep == 1) + { + bool hasLocation = AllWmsBaseLocations + .Where(t => t.locRow == (itemLocation.locRow % 2 == 1 ? (itemLocation.locRow + 1) : (itemLocation.locRow - 1))) + .Where(t => t.locColumn == itemLocation.locColumn) + .Where(t => t.locationStatus == "1" && string.IsNullOrEmpty(t.containerCode)) + .Any(); + if (!hasLocation) + { + Console.WriteLine(DateTime.Now + $":目标库位的浅库位库位状态异常,无法移库"); + _logger.Info($"目标库位的浅库位库位状态异常,无法移库"); + continue; + } + else + { + // 找到可以移库的目标库位 + toLocation = itemLocation; + break; + } + + } + else + { + // 找到可以移库的目标库位 + toLocation = itemLocation; + break; + } + + } + if (toLocation == null) + { + // 找寻下一个移库库位 + continue; + } + + var RemoveTask = new WcsTask() + { + objid = StaticData.SnowId.NextId(), + orderId = wmsProductOutstock.productOutstockId, + taskType = wmsProductOutstock.warehouseId == 231 ? StaticTaskType.SecondRemove : StaticTaskType.FiveRemove, + containerNo = wmsBaseLocation.containerCode, + createBy = "WCS", + createTime = DateTime.Now.AddSeconds(-10), + taskStatus = 0, + materialId = wmsProductOutstock.productId, + currPointId = wmsBaseLocation.locationId, + currPointNo = wmsBaseLocation.locationCode, + nextPointId = agvEquip.objid, + nextPointNo = agvEquip.equipNo, + endPointId = toLocation.locationId, + endPointNo = toLocation.locationCode, + equipmentNo = agvEquip.equipNo, + useFlag = 1, + qty = 1 + }; + SystemData.LockOutLocation(toLocation, dbContext); + SystemData.LockOutLocation(wmsBaseLocation, dbContext); + toLocation.locationStatus = "4"; + toLocation.updateBy = "WCS"; + toLocation.updateTime = DateTime.Now; + wmsBaseLocation.updateBy = "WCS"; + wmsBaseLocation.updateTime = DateTime.Now; + wmsBaseLocation.locationStatus = "4"; + dbContext.Update(toLocation); + dbContext.Update(wmsBaseLocation); + dbContext.Add(RemoveTask); + WcsTaskLog wcsTaskLog = CoreMapper.Map(RemoveTask); + dbContext.Add(wcsTaskLog); + targetLocation = item; + break; + #endregion + + } + else if(wmsBaseLocation.locationStatus == "1" && string.IsNullOrEmpty(wmsBaseLocation.containerCode)) + { + targetLocation = item; + break; + } + else if(wmsBaseLocation.locationStatus != "1") + { + //浅库位状态异常 + continue; + } + } + + } + + + WcsTask wcsTask = new WcsTask() + { + objid = StaticData.SnowId.NextId(), + orderId = wmsProductOutstock.productOutstockId, + taskType = wmsProductOutstock.warehouseId == 231 ? StaticTaskType.SecondStorageToLift : StaticTaskType.FiveProductOut, + containerNo = targetLocation.containerCode, + createBy = "WCS", + createTime = DateTime.Now, + taskStatus = 0, + materialId = wmsProductOutstock.productId, + currPointId = targetLocation.locationId, + currPointNo = targetLocation.locationCode, + nextPointId = agvEquip.objid, + nextPointNo = agvEquip.equipNo, + endPointId = endEquip.objid, + endPointNo = endEquip.equipNo, + equipmentNo = agvEquip.equipNo, + useFlag = 1, + qty = 1 + }; + SystemData.LockOutLocation(targetLocation, dbContext); + targetLocation.locationStatus = "6"; + targetLocation.updateBy = "WCS"; + targetLocation.updateTime = DateTime.Now; + dbContext.Update(targetLocation); + dbContext.Add(wcsTask); + + wmsProductOutstock.updateBy = "WCS"; + wmsProductOutstock.updateDate = DateTime.Now; + if (wmsProductOutstock.executeStatus == "0") + { + wmsProductOutstock.executeStatus = "1"; + wmsProductOutstock.beginTime = DateTime.Now; + } + dbContext.Update(wmsProductOutstock); + WmsProductOutstockDetail? wmsProductOutstockDetail = dbContext.WmsProductOutstockDetail.FirstOrDefault(x => x.productOutstockId == wmsProductOutstock.productOutstockId && x.locationCode == targetLocation.locationCode); + if (wmsProductOutstockDetail != null) + { + wmsProductOutstockDetail.executeStatus = "1"; + wmsProductOutstockDetail.updateBy = "WCS"; + wmsProductOutstockDetail.updateDate = DateTime.Now; + wmsProductOutstockDetail.beginTime = DateTime.Now; + dbContext.Update(wmsProductOutstockDetail); + } + dbContext.SaveChanges(); + + }catch (Exception ex) + { + Console.WriteLine(ex.Message + ex.StackTrace); + _logger.Error(ex.Message + "\n" + ex.StackTrace); + } + + } + + #endregion + + /// + /// 成品出库 + /// + private void CreateFiveProductTaskLogic() + { + using var scope = _host.Services.CreateScope(); + using var dbContext = scope.ServiceProvider.GetRequiredService(); + while (true) + { + var isCreate = false; + string message = ""; + try + { + dbContext.ChangeTracker.Clear(); + BaseEquip lineEquip = dbContext.BaseEquip.First(t => t.objid == 5); + if (lineEquip.equipStatus == 0) + { + bool task = dbContext.WcsTask.Where(t => t.nextPointId == 28 && t.taskStatus <= 5).Any(); + if (!task) + { + var proStock = dbContext.WmsProductStock + .Where(t => t.warehouseId == 531) + .Where(t => t.activeFlag == "1").ToList(); + var proOutStock = dbContext.WmsProductOutstock + .Where(t => t.outstockQty < t.applyQty) + .Where(t => t.auditStatus == "1") + .Where(t => t.warehouseId == 531) + .Where(t => t.operationType == "0") + .Where(t => t.productType == "3") + .Where(t => t.executeStatus == "0" || t.executeStatus == "1").ToList(); + //获取最早入库时间 + foreach (var item in proOutStock) + { + task = dbContext.WcsTask.Where(t => t.nextPointId == 28 && t.taskStatus <= 5).Any(); + if (!task) + { + BaseEquip endEquip = dbContext.BaseEquip.First(t => t.floorNo == 5 && t.equipType == 1); + + var wmsproStocks = proStock + .Where(t => t.productId == item.productId && t.saleOrderId == (item.saleOrderId == null ? 0 : item.saleOrderId) && t.warehouseId == item.warehouseId) + .Where(t => t.totalAmount > t.frozenAmount) + .Select(t => t.locationCode) + .ToList(); + List AllWmsBaseLocations = dbContext.WmsBaseLocation + .Where(t => t.activeFlag == "1") + .Where(t => t.delFlag == "0") + .Where(t => t.locationScrapType == "1") + .Where(t => t.locationStatus == "1") + .Where(t => t.warehouseId == item.warehouseId).ToList(); + var wmsBaseLocations = AllWmsBaseLocations + .Where(t => t.warehouseId == item.warehouseId) + .Where(t => wmsproStocks.Contains(t.locationCode)) + .ToList(); + + decimal needNumber = Convert.ToDecimal(item.applyQty - item.outstockQty); + if (needNumber <= 0) + { + item.executeStatus = "2"; + dbContext.Update(item); + dbContext.SaveChanges(); + continue; + } + + var bill = from a in wmsBaseLocations + from b in proStock + where a.locationCode == b.locationCode + select new { a, b }; + + BaseEquip agvEquip = StaticData.BaseEquip.First(t => t.objid == 28); + var inLocations = AllWmsBaseLocations.Where(t => t.locDeep == 1).Where(t => !string.IsNullOrEmpty(t.containerCode)).ToList(); + var outLocations = AllWmsBaseLocations.Where(t => t.locDeep == 2).Where(t => string.IsNullOrEmpty(t.containerCode)).ToList(); + var list = new List(); + foreach (var location in inLocations) + { + if (outLocations.Where(t => t.locRow == (location.locRow % 2 == 0 ? location.locRow - 1 : location.locRow + 1)) + .Where(t => t.locColumn == location.locColumn).Any()) + { + list.Add(location.locationCode); + } + } + bill = bill.OrderBy(t => list.Contains(t.a.locationCode) ? 0 : 1); + foreach (var b in bill) + { + item.executeStatus = "1"; + WmsBaseLocation location = b.a; + WmsProductStock stock = b.b; + WcsTask wcsTask; + stock.updateDate = DateTime.Now; + MesBasePalletInfo? mesBasePalletInfo = dbContext.MesBasePalletInfo.FirstOrDefault(t => t.palletInfoCode == stock.palletInfoCode); + if (mesBasePalletInfo != null) + { + if (location.locDeep == 1) + { + int? row = 0; + if (location.locRow % 2 == 1) + { + row = location.locRow + 1; + } + else + { + row = location.locRow - 1; + } + var lowLocationBill = bill.Where(t => t.a.locRow == row).Where(t => t.a.locColumn == location.locColumn).Where(t => t.a.warehouseId == location.warehouseId).FirstOrDefault(); + if (lowLocationBill != null) + { + location = lowLocationBill.a; + stock = lowLocationBill.b; + } + else + { + // 外侧浅库位 + WmsBaseLocation? wmsBaseLocation = dbContext.WmsBaseLocation.Where(t => t.locRow == row) + .Where(t => t.locColumn == location.locColumn) + .Where(t => t.warehouseId == location.warehouseId).FirstOrDefault(); + if (wmsBaseLocation.locationStatus == "1") + { + + WmsProductStock? wmsProductStock = dbContext.WmsProductStock.FirstOrDefault(t => t.locationCode == wmsBaseLocation.locationCode); + if (wmsProductStock != null) + { + #region 找寻移库目标库位 + + WmsBaseLocation? toLocation = null; + + + var moveLocationList = AllWmsBaseLocations.Where(t => t.warehouseId == location.warehouseId) + .Where(t => t.locationId != location.locationId) + .Where(t => string.IsNullOrEmpty(t.containerCode) && t.locationStatus == "1").OrderBy(t => t.locDeep).ToList(); + + foreach (WmsBaseLocation itemLocation in moveLocationList) + { + + if (itemLocation.locDeep == 1) + { + bool hasLocation = AllWmsBaseLocations + .Where(t => t.locRow == (itemLocation.locRow % 2 == 1 ? (itemLocation.locRow + 1) : (itemLocation.locRow - 1))) + .Where(t => t.locColumn == itemLocation.locColumn) + .Where(t => t.locationStatus == "1" && string.IsNullOrEmpty(t.containerCode)) + .Any(); + if (!hasLocation) + { + Console.WriteLine(DateTime.Now + $":目标库位的浅库位库位状态异常,无法移库"); + _logger.Info($"目标库位的浅库位库位状态异常,无法移库"); + continue; + } + else + { + // 找到可以移库的目标库位 + toLocation = itemLocation; + break; + } + + } + else + { + // 找到可以移库的目标库位 + toLocation = itemLocation; + break; + } + + } + if (toLocation == null) + { + // 找寻下一个可出库库存 + continue; + } + var RemoveTask = new WcsTask() + { + objid = StaticData.SnowId.NextId(), + orderId = item.productOutstockId, + taskType = StaticTaskType.FiveRemove, + containerNo = wmsBaseLocation.containerCode, + createBy = "WCS", + createTime = DateTime.Now.AddSeconds(-10), + taskStatus = 0, + materialId = item.productId, + currPointId = wmsBaseLocation.locationId, + currPointNo = wmsBaseLocation.locationCode, + nextPointId = agvEquip.objid, + nextPointNo = agvEquip.equipNo, + endPointId = toLocation.locationId, + endPointNo = toLocation.locationCode, + equipmentNo = agvEquip.equipNo, + useFlag = 1, + qty = 1 + }; + SystemData.LockOutLocation(toLocation, dbContext); + SystemData.LockOutLocation(wmsBaseLocation, dbContext); + toLocation.locationStatus = "4"; + toLocation.updateBy = "WCS"; + toLocation.updateTime = DateTime.Now; + wmsBaseLocation.updateBy = "WCS"; + wmsBaseLocation.updateTime = DateTime.Now; + wmsBaseLocation.locationStatus = "4"; + dbContext.Update(toLocation); + dbContext.Update(wmsBaseLocation); + dbContext.Add(RemoveTask); + WcsTaskLog wcsTaskLog = CoreMapper.Map(RemoveTask); + dbContext.Add(wcsTaskLog); + #endregion + //WmsBaseLocation? toLocation = AllWmsBaseLocations.Where(t => t.warehouseId == location.warehouseId) + // .Where(t => t.locDeep == 1) + // .Where(t => string.IsNullOrEmpty(t.containerCode)).FirstOrDefault(); + //toLocation ??= AllWmsBaseLocations.Where(t => t.warehouseId == location.warehouseId) + // .Where(t => t.warehouseId != location.locationId) + // .Where(t => string.IsNullOrEmpty(t.containerCode)) + // .FirstOrDefault(); + + //if (toLocation != null) + //{ + // if (toLocation.locDeep == 1) + // { + // bool hasLocation = AllWmsBaseLocations + // .Where(t => t.locRow == (toLocation.locRow % 2 == 1 ? (toLocation.locRow + 1) : (toLocation.locRow - 1))) + // .Where(t => t.locColumn == toLocation.locColumn) + // .Any(); + // if (!hasLocation) + // { + // Console.WriteLine(DateTime.Now + $":目标库位的浅库位库位状态异常,无法移库"); + // _logger.Info($"目标库位的浅库位库位状态异常,无法移库"); + // continue; + // } + // } + // var RemoveTask = new WcsTask() + // { + // objid = StaticData.SnowId.NextId(), + // orderId = item.productOutstockId, + // taskType = StaticTaskType.FiveRemove, + // containerNo = wmsProductStock.palletInfoCode, + // createBy = "WCS", + // createTime = DateTime.Now.AddSeconds(-10), + // taskStatus = 0, + // materialId = item.productId, + // currPointId = wmsBaseLocation.locationId, + // currPointNo = wmsBaseLocation.locationCode, + // nextPointId = agvEquip.objid, + // nextPointNo = agvEquip.equipNo, + // endPointId = toLocation.locationId, + // endPointNo = toLocation.locationCode, + // equipmentNo = agvEquip.equipNo, + // useFlag = 1, + // qty = 1 + // }; + // SystemData.LockOutLocation(toLocation, dbContext); + // SystemData.LockOutLocation(wmsBaseLocation, dbContext); + + // toLocation.locationStatus = "4"; + // toLocation.updateBy = "WCS"; + // toLocation.updateTime = DateTime.Now; + // wmsBaseLocation.updateBy = "WCS"; + // wmsBaseLocation.updateTime = DateTime.Now; + // wmsBaseLocation.locationStatus = "4"; + // dbContext.Update(toLocation); + // dbContext.Update(wmsBaseLocation); + // dbContext.Add(RemoveTask); + // WcsTaskLog wcsTaskLog = CoreMapper.Map(RemoveTask); + // dbContext.Add(wcsTaskLog); + //} + //else + //{ + // continue; + //} + } + else + { + // break; + } + } + else + { + message = "创建移库任务失败"; + Console.WriteLine(DateTime.Now + $":{wmsBaseLocation.locationCode}库位状态异常,无法移库"); + _logger.Info($"{wmsBaseLocation.locationCode}库位状态异常,无法移库"); + continue; + } + } + + } + //WmsProductOutstockDetail detail = new() + //{ + // productId = item.productId, + // productOutstockId = item.productOutstockId, + // locationCode = location.locationCode, + // executeStatus = "1", + // beginTime = DateTime.Now, + // warehouseId = item.warehouseId, + // erpAmount = 0, + // confirmAmount = 0, + // outstockAmount = 1, + // planAmount = 1, + // productBatch = item.productBatch, + // productOutstockDetailId = StaticData.SnowId.NextId(), + // productBarcode = mesBasePalletInfo.materialBarcode + //}; + //dbContext.Add(detail); + wcsTask = new WcsTask() + { + objid = StaticData.SnowId.NextId(), + orderId = item.productOutstockId, + taskType = StaticTaskType.FiveProductOut, + containerNo = stock.palletInfoCode, + createBy = "WCS", + createTime = DateTime.Now, + taskStatus = 0, + materialId = item.productId, + currPointId = location.locationId, + currPointNo = location.locationCode, + nextPointId = agvEquip.objid, + nextPointNo = agvEquip.equipNo, + endPointId = lineEquip.objid, + endPointNo = lineEquip.equipNo, + equipmentNo = agvEquip.equipNo, + useFlag = 1, + qty = 1 + }; + SystemData.LockOutLocation(location, dbContext); + location.locationStatus = "6"; + location.updateBy = "WCS"; + location.updateTime = DateTime.Now; + dbContext.Update(location); + dbContext.Add(wcsTask); + dbContext.Update(stock); + isCreate = true; + break; + } + } + if (item.beginTime == null) + { + item.beginTime = DateTime.Now; + } + dbContext.Update(item); + dbContext.SaveChanges(); + + } + } + + if (proOutStock.Count > 0) + { + if (isCreate) + { + SystemData.DeleteWaringLog(dbContext, WaringType.五楼出库任务创建失败); + } + else + { + SystemData.InsertWaringLog(dbContext, WaringType.五楼出库任务创建失败, message); + } + } + } + } + } + catch (Exception ex) + { + message += ex.Message; + Console.WriteLine(ex.Message + ex.StackTrace); + _logger.Error(ex.Message + "\n" + ex.StackTrace); + } + + Thread.Sleep(5000); + } + } + + /// + /// 成品出库 + /// + private void CreateSecondProductTaskLogic() + { + using var scope = _host.Services.CreateScope(); + using var dbContext = scope.ServiceProvider.GetRequiredService(); + while (true) + { + try + { + dbContext.ChangeTracker.Clear(); + BaseEquip lineEquip = dbContext.BaseEquip.First(t => t.objid == 2); + if (lineEquip.equipStatus == 0) + { + bool task = dbContext.WcsTask.Where(t => t.nextPointId == 8 && t.taskStatus <= 7).Any(); + if (!task) + { + lock (SystemData.SecondTaskLock) + { + var proStock = dbContext.WmsProductStock + .Where(t => t.warehouseId == 231) + .Where(t => t.activeFlag == "1") + .Where(t => t.totalAmount > t.frozenAmount) + .ToList(); + var proOutStock = dbContext.WmsProductOutstock + .Where(t => t.outstockQty < t.applyQty) + .Where(t => t.auditStatus == "1") + .Where(t => t.warehouseId == 231) + .Where(t => t.operationType == "0") + .Where(t => t.productType == "3") + .Where(t => t.executeStatus == "0" || t.executeStatus == "1").ToList(); + //获取最早入库时间 + foreach (var item in proOutStock) + { + task = dbContext.WcsTask.Where(t => t.nextPointId == 8 && t.taskStatus <= 7).Any(); + if (task) break; + + var wmsproStocks = proStock + .Where(t => t.productId == item.productId && t.saleOrderId == (item.saleOrderId == null ? 0 : item.saleOrderId) && t.warehouseId == item.warehouseId) + .Select(t => t.locationCode) + .ToList(); + List AllWmsBaseLocations = dbContext.WmsBaseLocation + .Where(t => t.activeFlag == "1") + .Where(t => t.delFlag == "0") + .Where(t => t.locationScrapType == "1") + .Where(t => t.locationStatus == "1") + .Where(t => t.warehouseId == item.warehouseId) + .Where(t => t.warehouseId == item.warehouseId).ToList(); + var wmsBaseLocations = AllWmsBaseLocations + .Where(t => t.warehouseId == item.warehouseId) + .Where(t => wmsproStocks.Contains(t.locationCode)) + .ToList(); + + decimal needNumber = Convert.ToDecimal(item.applyQty - item.outstockQty); + if (needNumber <= 0) + { + item.executeStatus = "2"; + dbContext.Update(item); + dbContext.SaveChanges(); + continue; + } + + var bill = from a in wmsBaseLocations + from b in proStock + where a.locationCode == b.locationCode + select new { a, b }; + WmsBaseLocation? location = null; + WmsProductStock? stock = null; + BaseEquip agvEquip = StaticData.BaseEquip.First(t => t.objid == 8); + BaseEquip endEquip = StaticData.BaseEquip.First(t => t.objid == 1); + var inLocations = AllWmsBaseLocations.Where(t => t.locDeep == 1).Where(t => !string.IsNullOrEmpty(t.containerCode)).ToList(); + var outLocations = AllWmsBaseLocations.Where(t => t.locDeep == 2).Where(t => string.IsNullOrEmpty(t.containerCode)).ToList(); + var list = new List(); + foreach (var loc in inLocations) + { + if (outLocations.Where(t => t.locRow == (loc.locRow % 2 == 0 ? loc.locRow - 1 : loc.locRow + 1)) + .Where(t => t.locColumn == loc.locColumn).Any()) + { + list.Add(loc.locationCode); + } + } + bill = bill.OrderBy(t => list.Contains(t.a.locationCode) ? 0 : 1); + foreach (var b in bill) + { + item.executeStatus = "1"; + location = b.a; + stock = b.b; + WcsTask wcsTask; + stock.updateDate = DateTime.Now; + MesBasePalletInfo? mesBasePalletInfo = dbContext.MesBasePalletInfo.FirstOrDefault(t => t.palletInfoCode == stock.palletInfoCode); + if (mesBasePalletInfo != null) + { + if (location.locDeep == 1)//如果是深库位 + { + int? row = 0; + if (location.locRow % 2 == 1) + { + row = location.locRow + 1; + } + else + { + row = location.locRow - 1; + } + var lowLocationBill = bill.Where(t => t.a.locRow == row).Where(t => t.a.locColumn == location.locColumn).Where(t => t.a.warehouseId == location.warehouseId).FirstOrDefault(); + if (lowLocationBill != null) + { //对应的浅库位满足条件,直接出浅库位 + location = lowLocationBill.a; + stock = lowLocationBill.b; + } + else + { + + // 目标出库库位对应的浅库位 + WmsBaseLocation? wmsBaseLocation = dbContext.WmsBaseLocation.Where(t => t.locRow == row) + .Where(t => t.locColumn == location.locColumn) + .Where(t => t.warehouseId == location.warehouseId).FirstOrDefault(); + + if (wmsBaseLocation != null && !string.IsNullOrEmpty(wmsBaseLocation.containerCode) && wmsBaseLocation.locationStatus == "1") + {//浅库位有库存 + WmsProductStock? wmsProductStock = dbContext.WmsProductStock.FirstOrDefault(t => t.locationCode == wmsBaseLocation.locationCode); + + #region 找寻移库目标库位 + // 寻找移库目的库位 + WmsBaseLocation? toLocation = null; + + + var moveLocationList = AllWmsBaseLocations.Where(t => t.warehouseId == location.warehouseId) + .Where(t => t.warehouseId != location.locationId) + .Where(t => string.IsNullOrEmpty(t.containerCode) && t.locationStatus == "1").OrderBy(t => t.locDeep).ToList(); + + foreach (WmsBaseLocation itemLocation in moveLocationList) + { + + if (itemLocation.locDeep == 1) + { + bool hasLocation = AllWmsBaseLocations + .Where(t => t.locRow == (itemLocation.locRow % 2 == 1 ? (itemLocation.locRow + 1) : (itemLocation.locRow - 1))) + .Where(t => t.locColumn == itemLocation.locColumn) + .Where(t => t.locationStatus == "1" && string.IsNullOrEmpty(t.containerCode)) + .Any(); + if (!hasLocation) + { + Console.WriteLine(DateTime.Now + $":目标库位的浅库位库位状态异常,无法移库"); + _logger.Info($"目标库位的浅库位库位状态异常,无法移库"); + continue; + } + else + { + // 找到可以移库的目标库位 + toLocation = itemLocation; + break; + } + + } + else + { + // 找到可以移库的目标库位 + toLocation = itemLocation; + break; + } + + } + if (toLocation == null) + { + // 找寻下一个可出库库存 + continue; + } + var RemoveTask = new WcsTask() + { + objid = StaticData.SnowId.NextId(), + orderId = item.productOutstockId, + taskType = StaticTaskType.SecondRemove, + containerNo = wmsBaseLocation.containerCode, + createBy = "WCS", + createTime = DateTime.Now.AddSeconds(-10), + taskStatus = 0, + materialId = item.productId, + currPointId = wmsBaseLocation.locationId, + currPointNo = wmsBaseLocation.locationCode, + nextPointId = agvEquip.objid, + nextPointNo = agvEquip.equipNo, + endPointId = toLocation.locationId, + endPointNo = toLocation.locationCode, + equipmentNo = agvEquip.equipNo, + useFlag = 1, + qty = 1 + }; + SystemData.LockOutLocation(toLocation, dbContext); + SystemData.LockOutLocation(wmsBaseLocation, dbContext); + toLocation.locationStatus = "4"; + toLocation.updateBy = "WCS"; + toLocation.updateTime = DateTime.Now; + wmsBaseLocation.updateBy = "WCS"; + wmsBaseLocation.updateTime = DateTime.Now; + wmsBaseLocation.locationStatus = "4"; + dbContext.Update(toLocation); + dbContext.Update(wmsBaseLocation); + dbContext.Add(RemoveTask); + WcsTaskLog wcsTaskLog = CoreMapper.Map(RemoveTask); + dbContext.Add(wcsTaskLog); + #endregion + } + else if (wmsBaseLocation.locationStatus != "1") + { + // 浅库位状态异常,找寻下一个可出库库存 + continue; + } + + } + } + + wcsTask = new WcsTask() + { + objid = StaticData.SnowId.NextId(), + orderId = item.productOutstockId, + taskType = StaticTaskType.SecondStorageToLift, + containerNo = stock.palletInfoCode, + createBy = "WCS", + createTime = DateTime.Now, + taskStatus = 0, + materialId = item.productId, + currPointId = location.locationId, + currPointNo = location.locationCode, + nextPointId = agvEquip.objid, + nextPointNo = agvEquip.equipNo, + endPointId = endEquip.objid, + endPointNo = endEquip.equipNo, + equipmentNo = agvEquip.equipNo, + useFlag = 1, + qty = 1 + }; + //WmsProductOutstockDetail detail = new() + //{ + // productId = item.productId, + // productOutstockId = item.productOutstockId, + // locationCode = location.locationCode, + // executeStatus = "1", + // beginTime = DateTime.Now, + // warehouseId = item.warehouseId, + // erpAmount = 0, + // confirmAmount = 0, + // outstockAmount = 1, + // planAmount = 1, + // productBatch = item.productBatch, + // productOutstockDetailId = StaticData.SnowId.NextId(), + // productBarcode = mesBasePalletInfo.materialBarcode, + //}; + //dbContext.Add(detail); + SystemData.LockOutLocation(location, dbContext); + location.locationStatus = "6"; + location.updateBy = "WCS"; + location.updateTime = DateTime.Now; + dbContext.Update(location); + dbContext.Add(wcsTask); + dbContext.Update(stock); + WcsTaskLog wcsTaskLog1 = CoreMapper.Map(wcsTask); + dbContext.Add(wcsTaskLog1); + dbContext.SaveChanges(); + break; + } + } + if (item.beginTime == null) + { + item.beginTime = DateTime.Now; + } + dbContext.Update(item); + dbContext.SaveChanges(); + } + } + } + } + } + catch (Exception ex) + { + Console.WriteLine(ex.Message + ex.StackTrace); + _logger.Error(ex.Message + "\n" + ex.StackTrace); + } + Thread.Sleep(5000); + } + } + + /// + /// 原材料出库 + /// + private void CreateRawTaskLogic() + { + using var scope = _host.Services.CreateScope(); + using var dbContext = scope.ServiceProvider.GetRequiredService(); + List taskType = new List() { "1", "2", "3" }; + while (true) + { + try + { + dbContext.ChangeTracker.Clear(); + + //原材料出库记录 + var rawOutStock = dbContext.WmsRawOutstock + .Where(t => t.executeStatus == "0" || t.executeStatus == "1") + .Where(t => t.outstockAmount > t.realOutstockAmount) + .Where(x => x.operationType == "0") + .Where(t => taskType.Contains(t.taskType)) + .Where(t => t.auditStatus == "1") + .ToList(); + List wcsTaskManuals = dbContext.WcsTaskManual.Where(t => t.nextPointId == 11).OrderBy(t => t.createBy).ToList(); + if (wcsTaskManuals.Count > 0) + { + int taskCount = dbContext.WcsTask.Where(t => t.nextPointId == 11).Count(); + //if (taskCount == 0 && wcsOutstockLock.qty == 0 && wcsOutstockLock.boxStatus == 0) + if (taskCount == 0) + { + List list = wcsTaskManuals.Where(t => t.taskType == 100).ToList(); + if (list.Count == 0) + { + list = wcsTaskManuals.Where(t => t.taskType == 30).ToList(); + } + if (list.Count == 0) + { + list = wcsTaskManuals.Where(t => t.taskType == 102).ToList(); + } + foreach (var wcs in list.Take(6)) + { + WcsTask wcsTask = CoreMapper.Map(wcs); + WcsTaskLog wcsTaskLog = CoreMapper.Map(wcsTask); + dbContext.Add(wcsTask); + dbContext.Add(wcsTaskLog); + dbContext.WcsTaskManual.Where(t => t.objid == wcs.objid).Delete(); + } + dbContext.SaveChanges(); + } + } + foreach (var item in rawOutStock) + { + if (item.endStationCode == "BB_01") + { + + } + decimal? RealOutNumber = item.realOutstockAmount; + var endEquip = dbContext.BaseEquip.FirstOrDefault(t => t.equipNo == item.endStationCode); + if (endEquip != null && endEquip.floorNo == 5) + { + + #region CTU出库,没用背负Agv的逻辑 + //if (endEquip.equipType == 8)//CTU出库 + //{ + // var wcsOutstockLock = dbContext.WcsOutstockLock.Where(t => t.warehouseId == 512).First(); + // if (wcsOutstockLock.qty == 0 && wcsOutstockLock.boxStatus == 0) + // { + // var wmsRawStocks = rawStock + // .Where(t => t.materialId == item.materialId) + // .Where(t => t.warehouseId == item.warehouseId) + // .Select(t => t.locationCode) + // .ToList(); + + // var wmsBaseLocations = dbContext.WmsBaseLocation + // .Where(t => t.activeFlag == "1") + // .Where(t => t.delFlag == "0") + // .Where(t => t.locationScrapType == "1") + // + // + // .Where(t => t.ContainerStatus == "1") + // .Where(t => t.warehouseId == item.warehouseId) + // .Where(t => wmsRawStocks.Contains(t.locationCode)) + // .ToList(); + + // decimal? needNumber = item.outstockAmount - RealOutNumber; + + // var bill = from a in wmsBaseLocations + // from b in rawStock + // where a.locationCode == b.locationCode + // select new { a, b }; + // //如果第一列满足需求,则按第一列排序,否则按最后一列排序 + // if (bill.Where(t => t.a.locColumn == 1).Select(t => t.b.totalAmount - t.b.frozenAmount).Sum() > needNumber) + // { + // bill = bill.OrderBy(t => t.a.locColumn).ToList(); + // } + // else + // { + // bill = bill.OrderByDescending(t => t.a.locColumn).ToList(); + // } + // //做数量限制 + + // //bill = bill.Take(5 - dbContext.WcsCmd.Where(t => t.cmdStatus < 3 && t.nextPointId == 20).Count()); + // bill = bill.Take(6); + // BaseEquip ctuEquip = StaticData.BaseEquip.First(t => t.objid == 11); + // BaseEquip lineEquip = StaticData.BaseEquip.First(t => t.objid == 20); + // foreach (var b in bill) + // { + // needNumber = item.outstockAmount - RealOutNumber; + // item.executeStatus = "1"; + // WmsBaseLocation location = b.a; + // WmsRawStock stock = b.b; + // WcsTask wcsTask; + // int qty = 0; + // if (stock.totalAmount - stock.frozenAmount <= needNumber)//该料箱全部出 + // { + // RealOutNumber += stock.totalAmount - stock.frozenAmount; + // qty = Convert.ToInt32(stock.totalAmount - stock.frozenAmount); + // stock.updateDate = DateTime.Now; + // } + // else + // { + // RealOutNumber += needNumber; + // qty = Convert.ToInt32(needNumber); + // stock.updateDate = DateTime.Now; + // } + // wcsTask = new WcsTask() + // { + // objid = StaticData.SnowId.NextId(), + // orderId = item.rawOutstockId, + // taskType = 38, + // containerNo = location.containerCode, + // createBy = "WCS", + // createTime = DateTime.Now, + // taskStatus = -1, + // materialId = item.materialId, + // currPointId = location.locationId, + // currPointNo = location.locationCode, + // nextPointId = ctuEquip.objid, + // nextPointNo = ctuEquip.equipNo, + // endPointId = lineEquip.objid, + // endPointNo = lineEquip.equipNo, + // equipmentNo = ctuEquip.equipNo, + // ud1 = location.locColumn, + // useFlag = 1, + // qty = qty + // }; + // MesBaseBarcodeInfo? mesBaseBarcodeInfo = dbContext.MesBaseBarcodeInfo.Where(t => t.barcodeInfo == stock.instockBatch).FirstOrDefault(); + // if (mesBaseBarcodeInfo != null) + // { + // WmsRawOutstockDetail wmsProductOutstockDetail = new WmsRawOutstockDetail() + // { + // rawOutstockDetailId = StaticData.SnowId.NextId(), + // rawOutstockId = item.rawOutstockId, + // materialId = item.materialId, + // createDate = DateTime.Now, + // createBy = "WCS", + // taskCode = wcsTask.objid.ToString(), + // executeStatus = "1", + // locationCode = location.locationCode, + // outstockAmount = qty, + // planAmount = item.outstockAmount, + // warehouseId = item.warehouseId, + // materialBarcode = mesBaseBarcodeInfo.barcodeInfo, + // instockBatch = mesBaseBarcodeInfo.batchCode, + // stackAmount = qty, + // outstockPerson = "WCS", + // outstockTime = DateTime.Now, + // outstockWay = "2", + // materialProductionDate = mesBaseBarcodeInfo.productionDate + // }; + // location.outstockFlag = "1"; + // location.locationStatus = "6"; + // location.updateBy = "WCS"; + // location.updateTime = DateTime.Now; + // wcsOutstockLock.boxStatus = 1; + // dbContext.Add(wmsProductOutstockDetail); + // dbContext.Update(location); + // dbContext.Add(wcsTask); + // dbContext.Update(stock); + // if (qty >= needNumber) + // { + // break; + // } + // } + // } + // if (item.beginTime == null) + // { + // item.beginTime = DateTime.Now; + // } + // dbContext.Update(wcsOutstockLock); + // dbContext.Update(item); + // dbContext.SaveChanges(); + // } + //}//CTU出库 + #endregion + if (endEquip.equipType == 10)//CTU出库到装配区 + { + lock (SystemData.outStockLock) + { + //原材料库存 + var rawStock = dbContext.WmsRawStock + + .Where(t => t.activeFlag == "1").ToList(); + BaseEquip endStationCodeEquip = dbContext.BaseEquip.First(t => t.objid == 10); + if (!string.IsNullOrEmpty(endStationCodeEquip.endStationCode) && endStationCodeEquip.IsOut == 1) + { + if (!endStationCodeEquip.endStationCode.Contains(item.endStationCode)) + { + continue; + } + bool CreateSuccess = false; + bool hasTask = dbContext.WcsTask.Where(t => t.nextPointId == 11).Any(); + if (!hasTask) + { + + var orderList = rawOutStock.Where(t => endStationCodeEquip.endStationCode.Contains(t.endStationCode)).ToList(); + + List tasks = new(); + List canOut = orderList.Select(t => t.saleOrderId).ToList(); + rawStock = rawStock.Where(t => canOut.Contains(t.saleOrderId)).OrderByDescending(t => t.saleOrderId).ToList(); + //对物料和数量进行分组 + var list = orderList.GroupBy(t => new { t.materialId, t.saleOrderId }).Select(t => new + { + MaterialId = t.Key.materialId, + SaleOrderId = t.Key.saleOrderId, + TotalAmount = t.Sum(x => x.outstockAmount), + realOutstockAmount = t.Sum(x => x.realOutstockAmount) + } + ).ToList(); + int? index = 1; + foreach (var order in list) + { + if (tasks.Count >= 6) + { + break; + } + var wmsRawStocks = rawStock + .Where(t => t.materialId == order.MaterialId && t.saleOrderId == (order.SaleOrderId == null ? 0 : order.SaleOrderId) && t.warehouseId == 512) + .Select(t => t.palletInfoCode) + .ToList(); + var AllWmsBaseLocations = dbContext.WmsBaseLocation.Where(t => t.warehouseId == 512).ToList(); + var wmsBaseLocations = AllWmsBaseLocations + .Where(t => t.activeFlag == "1") + .Where(t => t.delFlag == "0") + .Where(t => t.locationScrapType == "1") + .Where(t => t.locationStatus == "1") + .Where(t => t.warehouseId == 512) + .Where(t => t.ContainerStatus == "1") + .Where(t => wmsRawStocks.Contains(t.containerCode)) + .ToList(); + + decimal? needNumber = order.TotalAmount - order.realOutstockAmount; + // 寻找已经创建任务的料箱中的是否含有当前物料(A物料在料箱A\B中,然后找B物料的时候是否在料箱A\B中) + foreach (var task in tasks) + { + var wmsRawStock = rawStock.Where(t => t.palletInfoCode == task.containerNo && t.materialId == order.MaterialId && t.saleOrderId == order.SaleOrderId).ToList(); + decimal? total = wmsRawStock.Sum(t => t.totalAmount) - wmsRawStock.Sum(t => t.frozenAmount); + needNumber -= total; + WmsBaseLocation wmsBaseLocation = AllWmsBaseLocations.Where(t => t.locationCode == task.currPointNo).First(); + index = wmsBaseLocation.locRow; + } + if (needNumber <= 0) + { + continue; + } + var bill = from a in wmsBaseLocations + from b in rawStock + where a.containerCode == b.palletInfoCode && b.materialId == order.MaterialId && b.saleOrderId == (order.SaleOrderId == null ? 0 : order.SaleOrderId) + select new { a, b }; + //如果第一列满足需求,则按第一列排序,否则按最后一列排序 + if (bill.Where(t => t.a.locRow == index).Select(t => t.b.totalAmount - t.b.frozenAmount).Sum() >= needNumber) + { + if (index == 1) + { + if (bill.Where(t => t.b.totalAmount - t.b.frozenAmount >= needNumber).Any()) + { + bill = bill.OrderBy(t => t.a.locRow).ThenBy(t => t.a.locColumn) + .Where(t => t.b.totalAmount - t.b.frozenAmount >= needNumber) + .OrderBy(t => t.b.totalAmount - t.b.frozenAmount) + .ToList(); + } + else + { + bill = bill.OrderBy(t => t.a.locRow).ThenBy(t => t.a.locColumn) + .OrderByDescending(t => t.b.totalAmount - t.b.frozenAmount); + } + index = 2; + } + else + { + if (bill.Where(t => t.b.totalAmount - t.b.frozenAmount >= needNumber).Any()) + { + bill = bill.OrderByDescending(t => t.a.locRow).ThenBy(t => t.a.locColumn) + .OrderBy(t => t.b.totalAmount - t.b.frozenAmount) + .Where(t => t.b.totalAmount - t.b.frozenAmount >= needNumber) + .ToList(); + } + else + { + bill = bill.OrderByDescending(t => t.a.locRow).ThenBy(t => t.a.locColumn) + .OrderByDescending(t => t.b.totalAmount - t.b.frozenAmount); + } + index = 1; + } + } + else + { + bill = bill.OrderByDescending(t => t.a.locRow).ThenBy(t => t.a.locColumn).ToList(); + if (index == 1) + { + if (bill.Where(t => t.b.totalAmount - t.b.frozenAmount >= needNumber).Any()) + { + bill = bill.OrderByDescending(t => t.a.locRow).ThenBy(t => t.a.locColumn) + .OrderBy(t => t.b.totalAmount - t.b.frozenAmount) + .Where(t => t.b.totalAmount - t.b.frozenAmount >= needNumber) + .ToList(); + } + else + { + bill = bill.OrderByDescending(t => t.a.locRow).ThenBy(t => t.a.locColumn) + .OrderByDescending(t => t.b.totalAmount - t.b.frozenAmount); + } + index = 2; + } + else + { + if (bill.Where(t => t.b.totalAmount - t.b.frozenAmount >= needNumber).Any()) + { + bill = bill.OrderBy(t => t.a.locRow).ThenBy(t => t.a.locColumn) + .OrderBy(t => t.b.totalAmount - t.b.frozenAmount) + .Where(t => t.b.totalAmount - t.b.frozenAmount >= needNumber) + .ToList(); + } + else + { + bill = bill.OrderBy(t => t.a.locRow).ThenBy(t => t.a.locColumn) + .OrderByDescending(t => t.b.totalAmount - t.b.frozenAmount); + } + index = 1; + } + } + + BaseEquip ctuEquip = StaticData.BaseEquip.First(t => t.objid == 11); + BaseEquip lineEquip = StaticData.BaseEquip.First(t => t.objid == 20); + foreach (var b in bill) + { + if (needNumber <= 0 || tasks.Count >= 6) + { + break; + } + if (tasks.Where(t => t.containerNo == b.a.containerCode).Any())//判读当前料箱是否存在出库任务 + { + continue; + } + WmsBaseLocation location = b.a; + WmsRawStock stock = b.b; + int qty = 0; + if (stock.totalAmount - stock.frozenAmount <= needNumber)//该料箱全部出 + { + needNumber -= (stock.totalAmount - stock.frozenAmount); + qty = Convert.ToInt32(stock.totalAmount - stock.frozenAmount); + stock.updateDate = DateTime.Now; + } + else + { + qty = Convert.ToInt32(needNumber); + needNumber = 0; + stock.updateDate = DateTime.Now; + } + WmsRawOutstock? wmsRawOutstock = orderList.Where(t => t.materialId == order.MaterialId).FirstOrDefault(); + if (wmsRawOutstock != null) + { + var wcsTask = new WcsTask() + { + objid = StaticData.SnowId.NextId(), + orderId = wmsRawOutstock.rawOutstockId, + taskType = StaticTaskType.FiveAccessoryOut, + containerNo = location.containerCode, + createBy = "WCS", + createTime = DateTime.Now, + taskStatus = 0, + materialId = wmsRawOutstock.materialId, + currPointId = location.locationId, + currPointNo = location.locationCode, + nextPointId = ctuEquip.objid, + nextPointNo = ctuEquip.equipNo, + endPointId = lineEquip.objid, + endPointNo = lineEquip.equipNo, + equipmentNo = ctuEquip.equipNo, + ud1 = location.locColumn, + useFlag = 1, + qty = qty + }; + tasks.Add(wcsTask); + location.locationStatus = "6"; + location.updateBy = "WCS"; + // location.ContainerStatus = "2"; + location.updateTime = DateTime.Now; + dbContext.Update(location); + dbContext.Update(stock); + CreateSuccess = true; + if (tasks.Count >= 6) + { + break; + } + } + } + } + if (CreateSuccess) + { + endStationCodeEquip.IsOut = 0; + foreach (var orderItem in orderList) + { + if (orderItem.beginTime == null) + { + orderItem.beginTime = DateTime.Now; + } + orderItem.executeStatus = "1"; + } + BaseEquip startStationEquip = StaticData.BaseEquip.First(t => t.objid == 21); + BaseEquip bearAgvEquip = StaticData.BaseEquip.First(t => t.objid == 10); + var json = JsonConvert.DeserializeObject>(endStationCodeEquip.endStationCode); + BaseEquip endStationEquip = StaticData.BaseEquip.First(t => t.equipNo == json.First()); + hasTask = dbContext.WcsTask.Where(t => t.taskType == 32).Any(); + if (!hasTask) + { + WcsTask bearAgvTask = new() + { + objid = StaticData.SnowId.NextId(), + orderId = item.rawOutstockId, + taskType = 32, + containerNo = null, + currPointId = startStationEquip.objid, + currPointNo = startStationEquip.equipNo, + nextPointId = bearAgvEquip.objid, + nextPointNo = bearAgvEquip.equipNo, + endPointId = endStationEquip.objid, + endPointNo = endStationEquip.equipNo, + serialNo = SystemData.GetSerialNo(dbContext), + taskStatus = 0, + createTime = DateTime.Now, + createBy = "WCS", + materialId = item.materialId, + qty = 1, + useFlag = 1, + equipmentNo = startStationEquip.equipNo, + remark = "组装出库", + floorNo = 5, + masterId = item.materialId, + fromFloorNo = 5, + }; + dbContext.Add(bearAgvTask); + WcsTaskLog wcsTaskLog = CoreMapper.Map(bearAgvTask); + dbContext.Add(wcsTaskLog); + } + + if (item.beginTime == null) + { + item.beginTime = DateTime.Now; + } + dbContext.UpdateRange(orderList); + dbContext.Update(item); + } + dbContext.Update(endStationCodeEquip); + if (tasks.Count > 0) + { + dbContext.AddRange(tasks); + } + dbContext.SaveChanges(); + } + } + } + } + else + { + lock (SystemData.FiveTaskLock) + { + if (endEquip.equipType == 12)//原材料到柜体拆分区 + { + var rawStock = dbContext.WmsRawStock + .Where(t => t.activeFlag == "1").ToList();//查找有效的原材料库位 + bool hasTask = dbContext.WcsTask.Where(t => t.currPointId == endEquip.objid || t.endPointId == endEquip.objid).Any(); + if (!hasTask) + { + if (endEquip.emptyCount == 0) + { + var wmsRawStocks = rawStock + .Where(t => t.materialId == item.materialId && t.warehouseId == item.warehouseId) + .WhereIf(endEquip.equipType == 12, t => t.completeFlag == "1") + .Where(t => t.saleOrderId == (item.saleOrderId == null ? 0 : item.saleOrderId)) + .Where(t => t.totalAmount > t.frozenAmount) + .Select(t => t.palletInfoCode) + .ToList(); + List AllWmsBaseLocations = dbContext.WmsBaseLocation.Where(t => t.warehouseId == item.warehouseId).ToList(); + var wmsBaseLocations = AllWmsBaseLocations + .Where(t => t.activeFlag == "1") + .Where(t => t.delFlag == "0") + .Where(t => t.locationScrapType == "1") + .Where(t => t.locationStatus == "1") + .Where(t => t.warehouseId == item.warehouseId) + .OrderByDescending(t => t.locDeep) + .Where(t => wmsRawStocks.Contains(t.containerCode)) + .ToList(); + + decimal? needNumber = item.outstockAmount - item.realOutstockAmount; + + var bill = from a in wmsBaseLocations + from b in rawStock + where a.locationCode == b.locationCode + select new { a, b }; + + BaseEquip agvEquip = StaticData.BaseEquip.First(t => t.objid == 28); + BaseEquip lineEquip = StaticData.BaseEquip.First(t => t.equipNo == item.endStationCode); + var inLocations = AllWmsBaseLocations.Where(t => t.locDeep == 1).Where(t => !string.IsNullOrEmpty(t.containerCode)).ToList(); + var outLocations = AllWmsBaseLocations.Where(t => t.locDeep == 2).Where(t => string.IsNullOrEmpty(t.containerCode)).ToList(); + var list = new List(); + foreach (var location in inLocations) + { + if (outLocations.Where(t => t.locRow == (location.locRow % 2 == 0 ? location.locRow - 1 : location.locRow + 1)) + .Where(t => t.locColumn == location.locColumn).Any()) + { + list.Add(location.locationCode); + } + } + bill = bill.OrderBy(t => list.Contains(t.a.locationCode) ? 0 : 1); + foreach (var b in bill) + { + item.executeStatus = "1"; + WmsBaseLocation location = b.a; + WmsRawStock stock = b.b; + WcsTask wcsTask; + int qty = 0; + if (stock.totalAmount - stock.frozenAmount <= needNumber)//该料箱全部出 + { + qty = Convert.ToInt32(stock.totalAmount - stock.frozenAmount); + stock.updateDate = DateTime.Now; + } + else + { + qty = Convert.ToInt32(needNumber); + stock.updateDate = DateTime.Now; + } + MesBaseBarcodeInfo? mesBaseBarcodeInfo = dbContext.MesBaseBarcodeInfo.Where(t => t.barcodeInfo == stock.instockBatch).FirstOrDefault(); + if (mesBaseBarcodeInfo != null) + { + if (location.locDeep == 1) + { + int? row = 0; + if (location.locRow % 2 == 1)//五楼原材料与其他的深浅库位相反 + { + row = location.locRow + 1; + } + else + { + row = location.locRow - 1;//5 + } + var lowLocationBill = bill.Where(t => t.a.locRow == row).Where(t => t.a.locColumn == location.locColumn).Where(t => t.a.warehouseId == location.warehouseId).FirstOrDefault(); + if (lowLocationBill != null) + { + location = lowLocationBill.a; + stock = lowLocationBill.b; + } + else + { + WmsBaseLocation? wmsBaseLocation = AllWmsBaseLocations + .Where(t => t.locRow == row) + .Where(t => t.locColumn == location.locColumn) + .Where(t => t.warehouseId == location.warehouseId).FirstOrDefault(); + if (wmsBaseLocation.locationStatus == "1") + { + WmsRawStock? wmsRawStock = dbContext.WmsRawStock.FirstOrDefault(t => t.locationCode == wmsBaseLocation.locationCode); + if (wmsRawStock != null) + { + #region + // 寻找移库目的库位 + WmsBaseLocation? toLocation = null; + + + var moveLocationList = AllWmsBaseLocations.Where(t => t.warehouseId == location.warehouseId) + .Where(t => t.locationId != location.locationId) + .Where(t => string.IsNullOrEmpty(t.containerCode) && t.locationStatus == "1").OrderBy(t => t.locDeep).ToList(); + + foreach (WmsBaseLocation itemLocation in moveLocationList) + { + + if (itemLocation.locDeep == 1) + { + bool hasLocation = AllWmsBaseLocations + .Where(t => t.locRow == (itemLocation.locRow % 2 == 1 ? (itemLocation.locRow + 1) : (itemLocation.locRow - 1))) + .Where(t => t.locColumn == itemLocation.locColumn) + .Where(t => t.locationStatus == "1" && string.IsNullOrEmpty(t.containerCode)) + .Any(); + if (!hasLocation) + { + Console.WriteLine(DateTime.Now + $":目标库位的浅库位库位状态异常,无法移库"); + _logger.Info($"目标库位的浅库位库位状态异常,无法移库"); + continue; + } + else + { + // 找到可以移库的目标库位 + toLocation = itemLocation; + break; + } + + } + else + { + // 找到可以移库的目标库位 + toLocation = itemLocation; + break; + } + + } + if (toLocation == null) + { + // TODO : 没有找到可以移库的目标库位,添加报警 + SystemData.InsertWaringLog(dbContext, WaringType.五楼移库任务创建失败); + Console.WriteLine("5F原材料前往背板安装需要先移库,没有找到可以移库的目标库位,添加报警"); + Thread.Sleep(1000 * 5); + continue; + } + var RemoveTask = new WcsTask() + { + objid = StaticData.SnowId.NextId(), + orderId = item.rawOutstockId, + taskType = StaticTaskType.FiveRemove, + containerNo = wmsRawStock.palletInfoCode, + createBy = "WCS", + createTime = DateTime.Now.AddSeconds(-10), + taskStatus = 0, + materialId = item.materialId, + currPointId = wmsBaseLocation.locationId, + currPointNo = wmsBaseLocation.locationCode, + nextPointId = agvEquip.objid, + nextPointNo = agvEquip.equipNo, + endPointId = toLocation.locationId, + endPointNo = toLocation.locationCode, + equipmentNo = agvEquip.equipNo, + useFlag = 1, + qty = qty + }; + toLocation.locationStatus = "4"; + toLocation.updateBy = "WCS"; + toLocation.updateTime = DateTime.Now; + wmsBaseLocation.updateBy = "WCS"; + wmsBaseLocation.updateTime = DateTime.Now; + wmsBaseLocation.locationStatus = "4"; + dbContext.Update(toLocation); + dbContext.Update(wmsBaseLocation); + dbContext.Add(RemoveTask); + WcsTaskLog wcsTaskLog = CoreMapper.Map(RemoveTask); + dbContext.Add(wcsTaskLog); + #endregion + + } + else + { + // 可以出库 + // continue; + } + } + else if (wmsBaseLocation != null && wmsBaseLocation.locationStatus != "1") + { + Console.WriteLine(DateTime.Now + $":{wmsBaseLocation.locationCode}库位状态异常,无法移库"); + _logger.Info($"{wmsBaseLocation.locationCode}库位状态异常,无法移库"); + continue; + } + } + } + wcsTask = new WcsTask() + { + objid = StaticData.SnowId.NextId(), + orderId = item.rawOutstockId, + taskType = StaticTaskType.FiveRawToSplit,//如果是12那么就是原材料到柜体验收区,如果是13那么就是原材料到背板安装区 + containerNo = location.containerCode, + createBy = "WCS", + createTime = DateTime.Now, + taskStatus = 0, + materialId = item.materialId, + currPointId = location.locationId, + currPointNo = location.locationCode, + nextPointId = agvEquip.objid, + nextPointNo = agvEquip.equipNo, + endPointId = lineEquip.objid, + endPointNo = lineEquip.equipNo, + equipmentNo = agvEquip.equipNo, + useFlag = 1, + qty = qty + }; + //location是出库的库位,mesBaseBarcodeInfo是条码信息表数据,item是出库申请单 + //WmsRawOutstockDetail wmsProductOutstockDetail = new WmsRawOutstockDetail() + //{ + // rawOutstockDetailId = StaticData.SnowId.NextId(), + // rawOutstockId = item.rawOutstockId, + // materialId = item.materialId, + // createDate = DateTime.Now, + // createBy = "WCS", + // taskCode = wcsTask.objid.ToString(), + // executeStatus = "1", + // locationCode = location.locationCode, + // outstockAmount = qty, + // planAmount = item.outstockAmount, + // warehouseId = item.warehouseId, + // materialBarcode = mesBaseBarcodeInfo.barcodeInfo, + // instockBatch = mesBaseBarcodeInfo.batchCode, + // stackAmount = qty, + // outstockPerson = "WCS", + // outstockTime = DateTime.Now, + // outstockWay = "2", + // materialProductionDate = mesBaseBarcodeInfo.productionDate + //}; + //dbContext.Add(wmsProductOutstockDetail); + if (item.beginTime == null) + { + item.beginTime = DateTime.Now; + } + SystemData.LockOutLocation(location, dbContext); + location.locationStatus = "6"; + location.updateBy = "WCS"; + location.updateTime = DateTime.Now; + endEquip.emptyCount = 1; + dbContext.Update(endEquip); + dbContext.Update(location); + dbContext.Add(wcsTask); + dbContext.Update(item); + dbContext.Update(stock); + WcsTaskLog wcsTaskLog1 = CoreMapper.Map(wcsTask); + dbContext.Add(wcsTaskLog1); + dbContext.SaveChanges(); + SystemData.DeleteWaringLog(dbContext, WaringType.五楼移库任务创建失败); + } + + break; + } + } + } + } + else if (endEquip.equipType == 13) //原材料到背板安装 + { + var stock = dbContext.WmsRawStock.Where(t => t.instockBatch == item.materialBatch).FirstOrDefault(); + if (stock != null) + { + var location = dbContext.WmsBaseLocation + .Where(t => t.locationStatus == "1") + .Where(t => t.locationCode == stock.locationCode).FirstOrDefault(); + if (location != null) + { + List AllWmsBaseLocations = dbContext.WmsBaseLocation + .Where(t => t.warehouseId == item.warehouseId).ToList(); + decimal? needNumber = item.outstockAmount - item.realOutstockAmount; + BaseEquip agvEquip = StaticData.BaseEquip.First(t => t.objid == 28); + BaseEquip lineEquip = StaticData.BaseEquip.First(t => t.equipNo == item.endStationCode); + WcsTask wcsTask; + int qty = 0; + if (stock.totalAmount - stock.frozenAmount <= needNumber)//该料箱全部出 + { + qty = Convert.ToInt32(stock.totalAmount - stock.frozenAmount); + stock.updateDate = DateTime.Now; + } + else + { + qty = Convert.ToInt32(needNumber); + stock.updateDate = DateTime.Now; + } + MesBaseBarcodeInfo? mesBaseBarcodeInfo = dbContext.MesBaseBarcodeInfo.Where(t => t.barcodeInfo == stock.instockBatch).FirstOrDefault(); + if (mesBaseBarcodeInfo != null) + { + if (location.locationStatus != "1") + { + Console.WriteLine(DateTime.Now + $":{location.locationCode}库位状态异常,无法出库"); + _logger.Info($"{location.locationCode}库位状态异常,无法出库"); + continue; + } + if (location.locDeep == 1) + { + int? row = 0; + if (location.locRow % 2 == 1)//五楼原材料与其他的深浅库位相反 + { + row = location.locRow + 1; + } + else + { + row = location.locRow - 1;//5 + } + //对应的浅库位 + WmsBaseLocation? wmsBaseLocation = AllWmsBaseLocations + .Where(t => t.locRow == row) + .Where(t => t.locColumn == location.locColumn) + .Where(t => t.warehouseId == location.warehouseId).FirstOrDefault(); + + if (wmsBaseLocation.locationStatus == "1") + { + // 浅库位有库存 + WmsRawStock? wmsRawStock = dbContext.WmsRawStock.FirstOrDefault(t => t.locationCode == wmsBaseLocation.locationCode); + if (wmsRawStock != null) + { + // 寻找移库目的库位 + WmsBaseLocation? toLocation = null; + + + var moveLocationList = AllWmsBaseLocations.Where(t => t.warehouseId == location.warehouseId) + .Where(t => t.warehouseId != location.locationId) + .Where(t => string.IsNullOrEmpty(t.containerCode) && t.locationStatus == "1").OrderBy(t => t.locDeep).ToList(); + + foreach (WmsBaseLocation itemLocation in moveLocationList) + { + + if (itemLocation.locDeep == 1) + { + bool hasLocation = AllWmsBaseLocations + .Where(t => t.locRow == (itemLocation.locRow % 2 == 1 ? (itemLocation.locRow + 1) : (itemLocation.locRow - 1))) + .Where(t => t.locColumn == itemLocation.locColumn) + .Where(t => t.locationStatus == "1" && string.IsNullOrEmpty(t.containerCode)) + .Any(); + if (!hasLocation) + { + Console.WriteLine(DateTime.Now + $":目标库位的浅库位库位状态异常,无法移库"); + _logger.Info($"目标库位的浅库位库位状态异常,无法移库"); + continue; + } + else + { + // 找到可以移库的目标库位 + toLocation = itemLocation; + break; + } + + } + else + { + // 找到可以移库的目标库位 + toLocation = itemLocation; + break; + } + + } + if (toLocation == null) + { + // TODO : 没有找到可以移库的目标库位,添加报警 + SystemData.InsertWaringLog(dbContext, WaringType.五楼移库任务创建失败); + Console.WriteLine("5F原材料前往背板安装需要先移库,没有找到可以移库的目标库位,添加报警"); + continue; + } + var RemoveTask = new WcsTask() + { + objid = StaticData.SnowId.NextId(), + orderId = item.rawOutstockId, + taskType = StaticTaskType.FiveRemove, + containerNo = wmsRawStock.palletInfoCode, + createBy = "WCS", + createTime = DateTime.Now.AddSeconds(-10), + taskStatus = 0, + materialId = item.materialId, + currPointId = wmsBaseLocation.locationId, + currPointNo = wmsBaseLocation.locationCode, + nextPointId = agvEquip.objid, + nextPointNo = agvEquip.equipNo, + endPointId = toLocation.locationId, + endPointNo = toLocation.locationCode, + equipmentNo = agvEquip.equipNo, + useFlag = 1, + qty = qty + }; + toLocation.locationStatus = "4"; + toLocation.updateBy = "WCS"; + toLocation.updateTime = DateTime.Now; + wmsBaseLocation.updateBy = "WCS"; + wmsBaseLocation.updateTime = DateTime.Now; + wmsBaseLocation.locationStatus = "4"; + dbContext.Update(toLocation); + dbContext.Update(wmsBaseLocation); + dbContext.Add(RemoveTask); + WcsTaskLog wcsTaskLog = CoreMapper.Map(RemoveTask); + dbContext.Add(wcsTaskLog); + + } + else + { + //直接出 + } + + + } + else if (wmsBaseLocation.locationStatus != "1") + { + Console.WriteLine("浅库位状态异常,禁止出库,请检查浅库位状态"); + continue; + } + } + + //else + //{ + // Console.WriteLine(DateTime.Now + $":{location.locationCode}浅库位状态异常,无法移库"); + // _logger.Info($"{location.locationCode}浅库位状态异常,无法移库"); + // continue; + //} + } + wcsTask = new WcsTask() + { + objid = StaticData.SnowId.NextId(), + orderId = item.rawOutstockId, + taskType = StaticTaskType.FiveRawToBack,//如果是12那么就是原材料到柜体验收区,如果是13那么就是原材料到背板安装区 + containerNo = location.containerCode, + createBy = "WCS", + createTime = DateTime.Now, + taskStatus = 0, + materialId = item.materialId, + currPointId = location.locationId, + currPointNo = location.locationCode, + nextPointId = agvEquip.objid, + nextPointNo = agvEquip.equipNo, + endPointId = lineEquip.objid, + endPointNo = lineEquip.equipNo, + equipmentNo = agvEquip.equipNo, + useFlag = 1, + qty = qty + }; + //location是出库的库位,mesBaseBarcodeInfo是条码信息表数据,item是出库申请单 + //WmsRawOutstockDetail wmsProductOutstockDetail = new WmsRawOutstockDetail() + //{ + // rawOutstockDetailId = StaticData.SnowId.NextId(), + // rawOutstockId = item.rawOutstockId, + // materialId = item.materialId, + // createDate = DateTime.Now, + // createBy = "WCS", + // taskCode = wcsTask.objid.ToString(), + // executeStatus = "1", + // locationCode = location.locationCode, + // outstockAmount = qty, + // planAmount = item.outstockAmount, + // warehouseId = item.warehouseId, + // materialBarcode = mesBaseBarcodeInfo.barcodeInfo, + // instockBatch = mesBaseBarcodeInfo.batchCode, + // stackAmount = qty, + // outstockPerson = "WCS", + // outstockTime = DateTime.Now, + // outstockWay = "2", + // materialProductionDate = mesBaseBarcodeInfo.productionDate + //}; + if (item.beginTime == null) + { + item.beginTime = DateTime.Now; + } + SystemData.LockOutLocation(location, dbContext); + //dbContext.Add(wmsProductOutstockDetail); + location.locationStatus = "6"; + location.updateBy = "WCS"; + location.updateTime = DateTime.Now; + endEquip.emptyCount = 1; + dbContext.Update(endEquip); + dbContext.Update(location); + dbContext.Add(wcsTask); + dbContext.Update(item); + dbContext.Update(stock); + WcsTaskLog wcsTaskLog1 = CoreMapper.Map(wcsTask); + dbContext.Add(wcsTaskLog1); + SystemData.DeleteWaringLog(dbContext, WaringType.五楼移库任务创建失败); + dbContext.SaveChanges(); + } + } + } + } + } + } + } + } + catch (Exception ex) + { + _logger.Error(ex.Message + "\n" + ex.StackTrace); + } + Thread.Sleep(3000); + } + + } + } +} + diff --git a/src/Khd.Core.Wcs/Wcs/FirstFloor.cs b/src/Khd.Core.Wcs/Wcs/FirstFloor.cs new file mode 100644 index 0000000..8a081ed --- /dev/null +++ b/src/Khd.Core.Wcs/Wcs/FirstFloor.cs @@ -0,0 +1,870 @@ +using Khd.Core.Domain.Dto.TaskType; +using Khd.Core.Domain.Dto.waring; +using Khd.Core.Domain.Models; +using Khd.Core.EntityFramework; +using Khd.Core.Library; +using Khd.Core.Library.Mapper; +using Khd.Core.Plc.S7; +using Khd.Core.Wcs.Global; +using Masuit.Tools; +using Microsoft.EntityFrameworkCore; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; +using Z.EntityFramework.Plus; + +namespace Khd.Core.Wcs.Wcs +{ + /// + /// 一楼线程(包括接驳位,提升机调度) + /// + public class FirstFloor + { + private readonly LoggerUtils _logger = new LoggerUtils(); + private readonly IHost _host; + private readonly long F01 = 1; + private readonly long T01 = 6; + /// + /// 一楼RFID 读 + /// + private readonly BasePlcpoint RFID001; + /// + /// 到位信号 读 + /// + private readonly BasePlcpoint linesignal01; + /// + /// 提升机流水号 读 + /// + private readonly BasePlcpoint serialno06; + /// + /// 提升机状态 读 + /// + private readonly BasePlcpoint equipstate06; + /// + /// 提升机任务状态 读 + /// + private readonly BasePlcpoint hoistertrayin06; + /// + /// 提升机当前楼层 写 + /// + private readonly BasePlcpoint currentfloor06; + /// + /// 提升机目的楼层 写 + /// + private readonly BasePlcpoint targetfloor06; + /// + /// 提升机反馈流水号 + /// + private readonly BasePlcpoint reserialno06; + /// + /// 提升机手自动状态 + /// + private readonly BasePlcpoint hoisterStatus; + /// + /// 提升机到位信号 读 + /// + private readonly BasePlcpoint mesClose; + + /// + /// 提升机所有楼层报警灯控制闪烁 + /// + private BasePlcpoint hoisterAllLight; + + + public FirstFloor(IHost host) + { + this._host = host; + + //一楼RFID 读 + this.RFID001 = StaticData.BasePlcpointList.First(t => t.equipmentNo.Contains("FirstFloorLine") && t.plcpointNo.Contains("RFID001")); + //到位信号 读 + this.linesignal01 = StaticData.BasePlcpointList.First(t => t.equipmentNo.Contains("FirstFloorLine") && t.plcpointNo.Contains("linesignal01")); + //一楼提升机流水号 读 + this.serialno06 = StaticData.BasePlcpointList.First(t => t.equipmentNo.Contains("Hoister") && t.plcpointNo.Contains("serialno06")); + // Mes 关闭 + this.mesClose = StaticData.BasePlcpointList.First(t => t.equipmentNo.Contains("Hoister") && t.plcpointNo.Contains("mesclose")); + //一楼提升机状态 读 + this.equipstate06 = StaticData.BasePlcpointList.First(t => t.equipmentNo.Contains("Hoister") && t.plcpointNo.Contains("equipstate06")); + //一楼提升机任务状态 读 + this.hoistertrayin06 = StaticData.BasePlcpointList.First(t => t.equipmentNo.Contains("Hoister") && t.plcpointNo.Contains("hoistertrayin06")); + //一楼提升机当前楼层 写 + this.currentfloor06 = StaticData.BasePlcpointList.First(t => t.equipmentNo.Contains("Hoister") && t.plcpointNo.Contains("currentfloor06")); + //一楼提升机目的楼层 写 + this.targetfloor06 = StaticData.BasePlcpointList.First(t => t.equipmentNo.Contains("Hoister") && t.plcpointNo.Contains("targetfloor06")); + //一楼提升机到位信号 读 + this.reserialno06 = StaticData.BasePlcpointList.First(t => t.equipmentNo.Contains("Hoister") && t.plcpointNo.Contains("reserialno06")); + //提升机手自动状态 + this.hoisterStatus = StaticData.BasePlcpointList.First(t => t.equipmentNo.Contains("Hoister") && t.plcpointNo.Contains("hoisterStatus")); + } + + /// + /// 启动上件扫描监听 + /// + public void StartPoint() + { + Thread firstFloorLine = new(FirstFloorLine)//一楼接驳位线程 + { + IsBackground = true, + Name = "FirstFloorLine" + }; + firstFloorLine.Start(); + + Thread firstFloorHoister = new(FirstFloorHoister)//提升机 + { + IsBackground = true, + Name = "FirstFloorHoister" + }; + firstFloorHoister.Start(); + + Thread equipStatusThread = new Thread(EquipStatusLogic)//设备状态,1-5楼接驳位能不能送货,提升机和小车任务 + { + IsBackground = true, + Name = "EquipStatusThread" + }; + equipStatusThread.Start(); + + Console.WriteLine(DateTime.Now + ":一楼提升机线程启动成功"); + _logger.Info("一楼提升机线程启动成功"); + } + + private void EquipStatusLogic(object? obj) + { + using var scope = this._host.Services.CreateScope(); + using var dbContext = scope.ServiceProvider.GetRequiredService(); + while (true) + { + try + { + for (int i = 1; i <= 5; i++) + { + BasePlcpoint basePlcpoint = StaticData.BasePlcpointList.First(t => t.plcpointNo == $"linesignal0{i}"); + var lineSignal = StaticData.PlcDic[0].Read(basePlcpoint.plcpointAddress); + if (lineSignal != null) + { + if (Convert.ToInt32(lineSignal) == 1) + { + BaseEquip baseEquip = dbContext.BaseEquip.First(t => t.objid == i); + if (baseEquip.equipStatus != 1)//不是忙碌状态,改为忙碌状态 + { + baseEquip.equipStatus = 1; + dbContext.Update(baseEquip); + dbContext.SaveChanges(); + } + //else + //{ + // bool hasTask = dbContext.WcsTask.Where(t => t.endPointId == i || t.currPointId == i).Any(); + // if (!hasTask) + // { + // baseEquip.equipStatus = 0; + // dbContext.Update(baseEquip); + // dbContext.SaveChanges(); + // } + //} + } + else + { + BaseEquip baseEquip = dbContext.BaseEquip.First(t => t.objid == i); + //bool hasCmd = dbContext.WcsCmd.Where(t => t.nextPointId == i || t.currPointId == i).Any();//小车任务 + bool hasTask = dbContext.WcsTask.Where(t => (t.endPointId == i) && t.taskStatus >= 1 && t.nextPointId == 6).Any();//提升机任务,有没有正在执行的往这个接驳位送的 + bool hascmd = dbContext.WcsTask.Where(t => (t.endPointId == i) && t.taskStatus >= 1 && t.nextPointId != 6).Any();//提升机任务,有没有正在执行的往这个接驳位送的 + if (hascmd || hasTask) + { + baseEquip.containerNo = null; + baseEquip.equipStatus = 1; + } + else//接驳位改为忙碌状态 + { + baseEquip.containerNo = null; + baseEquip.equipStatus = 0; + } + dbContext.Update(baseEquip); + dbContext.SaveChanges(); + } + } + } + } + catch (Exception ex) + { + if (ex is PlcException) + { + + } + else + { + _logger.Error(ex.Message + "\n" + ex.StackTrace); + } + } + Thread.Sleep(1000); + } + } + + private void CallEmpty() + { + using var scope = _host.Services.CreateScope(); + using var dbContext = scope.ServiceProvider.GetRequiredService(); + BasePlcpoint oneOutPoint = StaticData.BasePlcpointList.First(t => t.plcpointNo == "oneOut"); + BasePlcpoint someOutPoint = StaticData.BasePlcpointList.First(t => t.plcpointNo == "someOut"); + BaseEquip mdjEquip = StaticData.BaseEquip.First(t => t.objid == 40); + while (true) + { + try + { + dbContext.ChangeTracker.Clear(); + var linesignal = StaticData.PlcDic[0].Read(this.linesignal01.plcpointAddress); + int taskCount = dbContext.WcsTask.Where(t => t.nextPointId == 6 && t.taskStatus > 0 && t.endPointId == 1).Count(); + int firstFloorCount = dbContext.WcsTask.Where(t => t.currPointId == 1).Count(); + if (Convert.ToInt32(linesignal) == 0 && taskCount == 0 && firstFloorCount == 0) + { + bool canSend = dbContext.WcsTask.Where(t => t.floorNo == 1).Where(t => t.taskStatus > 0).Any(); + if (!canSend) + { + WcsTaskManual? wcsTaskManual = dbContext.WcsTaskManual.Where(t => t.nextPointId == 40).FirstOrDefault(); + if (wcsTaskManual != null) + { + if (wcsTaskManual.taskType == 53) + { + StaticData.PlcDic[0].WriteToPoint(someOutPoint.plcpointAddress, "1", someOutPoint.plcpointLength.ToString()); + WcsTask wcsTask = CoreMapper.Map(wcsTaskManual); + wcsTask.createTime = DateTime.Now; + wcsTask.createBy = "一楼接驳位线程"; + wcsTask.taskStatus = 0; + wcsTask.useFlag = 1; + wcsTask.isEmpty = "1"; + wcsTask.qty = mdjEquip.emptyCount; + wcsTask.remark = "一楼创建入库任务"; + WcsTaskLog wcsTaskLog = CoreMapper.Map(wcsTask); + mdjEquip.emptyCount = 0; + dbContext.Update(mdjEquip); + dbContext.Add(wcsTaskLog); + dbContext.Add(wcsTask); + dbContext.SaveChanges(); + _logger.Info("一楼接驳位线程:空托盘任务下发成功"); + Console.WriteLine(DateTime.Now + ":一楼接驳位线程:空托盘任务下发成功"); + } + } + } + } + } + catch (Exception ex) + { + if (ex is PlcException) + { + + } + else + { + _logger.Error(ex.Message + "\n" + ex.StackTrace); + } + } + Thread.Sleep(1000); + } + } + + public static bool ReadEmptyLocation() + { + var oneOutPoint = StaticData.BasePlcpointList.First(t => t.plcpointNo == "oneOut"); + var someOutPoint = StaticData.BasePlcpointList.First(t => t.plcpointNo == "someOut"); + var oneInPoint = StaticData.BasePlcpointList.First(t => t.plcpointNo == "oneIn"); + var someInPoint = StaticData.BasePlcpointList.First(t => t.plcpointNo == "someIn"); + var oneOutValue = StaticData.PlcDic[0].Read(oneOutPoint.plcpointAddress); + var someOutValue = StaticData.PlcDic[0].Read(someOutPoint.plcpointAddress); + var oneInValue = StaticData.PlcDic[0].Read(oneInPoint.plcpointAddress); + var someInValue = StaticData.PlcDic[0].Read(someInPoint.plcpointAddress); + if (oneOutValue != null && someOutValue != null && oneInValue != null && someInValue != null) + { + if (Convert.ToInt32(oneOutValue) == 0 && Convert.ToInt32(someOutValue) == 0 && Convert.ToInt32(oneInValue) == 0 && Convert.ToInt32(someInValue) == 0) + { + return true; + } + } + return false; + } + + /// + /// 启动一楼接驳位线程 + /// + private void FirstFloorLine() + { + List Outtpyes = new() { 2, 4, 8, 6 }; + using var scope = _host.Services.CreateScope(); + using var dbContext = scope.ServiceProvider.GetRequiredService(); + while (true) + { + try + { + dbContext.ChangeTracker.Clear();//上次查出1,不加这行,数据库实际2,查出1 + var RFID001Value = StaticData.PlcDic[0].ReadRFID(this.RFID001.plcpointAddress); //一楼RFID 读 + var linesignal01Value = StaticData.PlcDic[0].Read(this.linesignal01.plcpointAddress); //到位信号 读 + //正常读到plc值 + if (linesignal01Value != null && RFID001Value != null) + { + //正常托盘到位 + BaseEquip baseEquip = dbContext.BaseEquip.First(t => t.objid == 1); + if (Convert.ToInt32(linesignal01Value) == 1) + { + var wcsTasks = dbContext.WcsTask.ToList(); + //判断task表里没有该rfid的未完成的入库 + //信息,未下发去向 + var task = wcsTasks.Where(t => t.IsDelete == 0 || t.IsDelete == null) + .Where(t => t.nextPointId == 1) + .OrderBy(t => t.createTime).FirstOrDefault(); + + if (task == null) + { + if (StaticData.BigContainerCodes.Contains(RFID001Value)) + { + var newTask = new WcsTask() + { + objid = StaticData.SnowId.NextId(), + serialNo = SystemData.GetSerialNo(dbContext), + equipmentNo = "F01", + taskType = 5, + taskStatus = 0, + containerNo = RFID001Value, + currPointId = F01, + currPointNo = "TSJ_01", + nextPointId = T01, + nextPointNo = "TSJ_01", + fromFloorNo = 1, + floorNo = 4, + useFlag = 1, + ud1 = 20, + createBy = "一楼接驳位", + createTime = DateTime.Now, + remark = "一楼创建入库任务" + }; + WcsTaskLog wcsTaskLog = CoreMapper.Map(newTask); + dbContext.Add(wcsTaskLog); + dbContext.Add(newTask); + dbContext.SaveChanges(); + } + else + { + var hasTask = wcsTasks.Where(t => t.containerNo == RFID001Value).Any(); + if (!hasTask) + { + //根据托盘号获取物料码 + var material = dbContext.MesBasePalletInfo.Where(t => t.palletInfoCode == RFID001Value).FirstOrDefault(); + WcsTaskLog? taskLog = dbContext.WcsTaskLog.Where(t => t.containerNo == RFID001Value).OrderByDescending(t => t.createTime).FirstOrDefault(); + + if (material != null) + { + if (string.IsNullOrEmpty(material.materialBarcode)) + { + continue; + } + bool hasBarInfo = dbContext.MesBaseBarcodeInfo.Where(t => t.palletInfoCode == RFID001Value && t.barcodeInfo == material.materialBarcode).Any(); + if (!hasBarInfo) + { + continue; + } + if (taskLog != null) + { + if (taskLog.materialBarcode == material.materialBarcode) + { + if (baseEquip.containerNo == "0") + { + baseEquip.containerNo = null; + dbContext.Update(baseEquip); + dbContext.SaveChanges(); + _logger.Info("一楼接驳位线程:托盘" + RFID001Value + "解绑信息更新成功"); + } + else if (baseEquip.containerNo != RFID001Value) + { + baseEquip.containerNo = RFID001Value; + dbContext.Update(baseEquip); + dbContext.SaveChanges(); + _logger.Info("一楼接驳位线程:托盘" + RFID001Value + "绑定信息更新成功"); + Console.WriteLine(DateTime.Now + ":一楼接驳位线程:托盘" + RFID001Value + "绑定信息更新成功"); + Thread.Sleep(3000); + continue; + } + else + { + Thread.Sleep(3000); + continue; + } + } + } + + var warehouseId = dbContext.WmsWarehouseMaterial.Where(t => t.storageType == "1" && t.storageId == material.materialId).FirstOrDefault()?.warehouseId; + if (warehouseId != null) + { + var TargetFloor = dbContext.WmsBaseWarehouse.Where(t => t.warehouseId == warehouseId).FirstOrDefault(); + if (TargetFloor != null) + { + BaseEquip baseEquip1 = dbContext.BaseEquip.First(t => t.objid == TargetFloor.warehouseFloor); + //插入task表 + + var dic = StaticData.BaseDictionary.Where(t => t.dicKey == "TaskType" && t.agvType == "I" && t.dicField == TargetFloor.warehouseInstockType).FirstOrDefault(); + if (dic != null) + { + var newTask = new WcsTask() + { + objid = StaticData.SnowId.NextId(), + serialNo = SystemData.GetSerialNo(dbContext), + equipmentNo = "F01", + taskType = Convert.ToInt32(dic.dicValue), + taskStatus = 0, + containerNo = RFID001Value, + materialBarcode = material.materialBarcode, + materialId = material.materialId, + qty = Convert.ToInt32(material.bindAmount), + currPointId = F01, + currPointNo = "TSJ_01", + nextPointId = T01, + nextPointNo = "TSJ_01", + ud1 = 20, + endPointId = baseEquip1.objid, + endPointNo=baseEquip1.equipNo, + fromFloorNo = 1, + floorNo = TargetFloor.warehouseFloor, + useFlag = 1, + createBy = "一楼接驳位", + createTime = DateTime.Now, + remark = "一楼创建入库任务" + }; + WcsTaskLog wcsTaskLog = CoreMapper.Map(newTask); + dbContext.Add(wcsTaskLog); + dbContext.Add(newTask); + dbContext.SaveChanges(); + } + } + } + else + { + + SystemData.InsertWaringLog(dbContext, WaringType.绑定物料无仓库信息, "一楼接驳位物料未绑定仓库信息"); + continue; + } + } + } + } + } + else + { + if (string.IsNullOrEmpty(task.containerNo))//人工调出 + { + if (task.useFlag == 1) + { + if (task.qty > 1)//多个托盘 + { + if (task.endPointId != 1) + { + task.nextPointId = 6; + dbContext.SaveChanges(); + } + } + else if (task.qty == 1) + { + if (task.endPointId != 1) + { + task.nextPointId = 6; + task.containerNo = RFID001Value; + dbContext.SaveChanges(); + } + } + } + } + else + { + MesBasePalletInfo? mesBasePalletInfo = dbContext.MesBasePalletInfo.FirstOrDefault(t => t.palletInfoCode == RFID001Value); + if (mesBasePalletInfo != null) + { + MesBaseBarcodeInfo? mesBaseBarcodeInfo = dbContext.MesBaseBarcodeInfo.Where(t => t.palletInfoCode == RFID001Value).FirstOrDefault(); + if (mesBaseBarcodeInfo != null) + { + mesBaseBarcodeInfo.palletInfoCode = null; + dbContext.Update(mesBaseBarcodeInfo); + } + mesBasePalletInfo.bindAmount = null; + mesBasePalletInfo.bindAmount = null; + mesBasePalletInfo.materialBarcode = null; + mesBasePalletInfo.materialCode = null; + mesBasePalletInfo.materialId = null; + mesBasePalletInfo.materialName = null; + mesBasePalletInfo.updateBy = "WCS"; + mesBasePalletInfo.updateTime = DateTime.Now; + dbContext.Update(mesBasePalletInfo); + dbContext.Remove(task); + dbContext.WcsTaskLog.Where(t => t.objid == task.objid).Update(t => new WcsTaskLog { taskStatus = 6 }); + dbContext.SaveChanges(); + } + } + } + } + } + } + catch (Exception ex) + { + if (ex is PlcException) + { + + } + else + { + _logger.Error(ex.Message + "\n" + ex.StackTrace); + } + } + SystemData.DeleteWaringLog(dbContext, WaringType.绑定物料无仓库信息); + Thread.Sleep(3000); + } + } + + /// + /// 提升机线程 + /// + private void FirstFloorHoister() + { + using var scope = _host.Services.CreateScope(); + using var dbContext = scope.ServiceProvider.GetRequiredService(); + List Outtpyes = new();//有问题的楼层任务 + string warningMsg = "任务无法下发"; + while (true) + { + using var transaction = dbContext.Database.BeginTransaction(); + try + { + Outtpyes.Clear(); + var mesCloseValue = StaticData.PlcDic[0].Read(this.mesClose.plcpointAddress); //MES关闭状态 读 + var serialno06Value = StaticData.PlcDic[0].Read(this.serialno06.plcpointAddress); //提升机流水号 读 + var equipstate06Value = StaticData.PlcDic[0].Read(this.equipstate06.plcpointAddress); //提升机状态 读 + var hoisterTrayIn06Value = StaticData.PlcDic[0].Read(this.hoistertrayin06.plcpointAddress); //提升机货物到位状态 读 + var currentfloor06Value = StaticData.PlcDic[0].Read(this.currentfloor06.plcpointAddress); //提升机当前楼层 读 + var targetfloor06Value = StaticData.PlcDic[0].Read(this.targetfloor06.plcpointAddress); //提升机目的楼层 写 + var hoisterStatusValue = StaticData.PlcDic[0].Read(this.hoisterStatus.plcpointAddress); //提升机目的楼层 写 + var reserialno06 = StaticData.PlcDic[0].Read(this.reserialno06.plcpointAddress); //反馈流水号 + if (mesCloseValue != null && hoisterStatusValue != null && Convert.ToInt32(hoisterStatusValue) == 1 && Convert.ToInt32(mesCloseValue) == 0) + { + //正常读到plc值 + if (targetfloor06Value != null && serialno06Value != null && equipstate06Value != null && currentfloor06Value != null && reserialno06 != null && hoisterTrayIn06Value != null) + { + //提升机空闲 + if (Convert.ToInt32(equipstate06Value) == 0) + { + dbContext.ChangeTracker.Clear(); + var wcsTasks = dbContext.WcsTask.Where(t => t.nextPointId == T01 && t.taskStatus < 5) + .OrderBy(t => t.ud1).OrderBy(t => t.createTime).ToList(); + foreach (var wcsTask in wcsTasks) + { + Outtpyes.Add(wcsTask.floorNo.Value); + if (wcsTask.taskType == StaticTaskType.SecondTransitToLift && !string.IsNullOrEmpty(wcsTask.containerNo)) + { + var mesBasePalletInfo = dbContext.MesBasePalletInfo + .Where(t => t.palletInfoCode == wcsTask.containerNo).FirstOrDefault(); + if (mesBasePalletInfo == null || string.IsNullOrEmpty(mesBasePalletInfo.materialBarcode)) + { + warningMsg = "2楼周转位废料到3楼,托盘未绑定条码,请先绑定"; + continue; + } + var mesBaseBarcodeInfo = dbContext.MesBaseBarcodeInfo + .Where(t => t.palletInfoCode == wcsTask.containerNo && t.barcodeInfo == mesBasePalletInfo.materialBarcode).FirstOrDefault(); + if (mesBaseBarcodeInfo == null) + { + warningMsg = "2楼周转位废料到3楼,未找到条码信息,请确认"; + continue; + } + } + _logger.Info($"当前任务?{wcsTask.ToJsonString()}"); + bool CanExecute = false; + long agvEquip = 0; + List taskType = new(); + if (wcsTask.floorNo == 3) + { + agvEquip = 9; + taskType.Add(StaticTaskType.ThirdTransitToLift); + taskType.Add(StaticTaskType.ThirdStockReturnTask); + } + else if (wcsTask.floorNo == 5) + { + agvEquip = 28; + taskType.Add(StaticTaskType.FiveStockReturnTask); + taskType.Add(StaticTaskType.FiveProductOut); + } + else if (wcsTask.floorNo == 2) + { + agvEquip = 8; + taskType.Add(StaticTaskType.SecondStorageToLift); + taskType.Add(StaticTaskType.SecondTransitToLift); + } + else + { + CanExecute = true; + } + if (!CanExecute) + { + CanExecute = !dbContext.WcsTask.Where(t => taskType.Contains(t.taskType.Value) && t.nextPointId == agvEquip).Any(); + } + if (CanExecute) + { + wcsTask.serialNo ??= SystemData.GetSerialNo(dbContext); + if (wcsTasks.Where(t => t.taskStatus > 0).Where(t => t.objid != wcsTask.objid).Any()) + { + warningMsg = $"提升机线程:目的楼层{wcsTask.floorNo}有其他任务正在执行,跳过当前任务"; + _logger.Info("提升机线程:目的楼层有其他任务正在执行,跳过当前任务"); + continue; + } + BaseEquip lineEquip = dbContext.BaseEquip.First(t => t.objid == wcsTask.floorNo); + if (wcsTask.taskStatus == 0 && Convert.ToInt32(hoisterTrayIn06Value) == 0)//创建状态,并且里面没有货物 + { + // 目的楼层从接驳位出发入库的任务 --待测试 + var InTask = dbContext.WcsTask.FirstOrDefault(t => t.currPointId == lineEquip.objid); + + if (lineEquip.equipStatus == 1 && InTask == null) + { + warningMsg = $"提升机目的楼层{wcsTask.floorNo}楼接驳位有物体或任务正在执行,跳过当前任务"; + _logger.Info($"提升机目的楼层{wcsTask.floorNo}楼接驳位有物体或任务正在执行,跳过当前任务"); + continue; + } + BasePlcpoint floorPoint = StaticData.BasePlcpointList.First(t => t.plcpointNo == "RFID00" + wcsTask.fromFloorNo); + string? rfid = StaticData.PlcDic[0].ReadRFID(floorPoint.plcpointAddress); + _logger.Info($"{wcsTask.fromFloorNo}楼RFID?{rfid},任务RFID{wcsTask.containerNo}"); + if (wcsTask.containerNo == rfid || (string.IsNullOrEmpty(wcsTask.containerNo) && wcsTask.qty > 1 || wcsTask.taskType == 99)) + { + if (Convert.ToInt32(currentfloor06Value) == wcsTask.fromFloorNo)//当前楼层和起始楼层一致 + { + wcsTask.taskStatus = 2; + wcsTask.updateBy = "提升机线程"; + wcsTask.updateTime = DateTime.Now; + wcsTask.remark = "提升机任务执行中"; + BasePlcpoint basePlcpoint = StaticData.BasePlcpointList.First(t => t.floorNo == wcsTask.fromFloorNo && t.plcpointNo.Contains("wcsrun")); + dbContext.Update(wcsTask); + dbContext.WcsTaskLog.Where(t => t.objid == wcsTask.objid).Update(t => new WcsTaskLog { taskStatus = 2, updateBy = "提升机线程", updateTime = DateTime.Now, remark = "提升机任务执行中" }); + lineEquip.equipStatus = 1; + dbContext.Update(lineEquip); + dbContext.SaveChanges(); + StaticData.PlcDic[0].WriteToPoint(basePlcpoint.plcpointAddress, "1", basePlcpoint.plcpointLength.ToString()); + StaticData.PlcDic[0].WriteToPoint(this.serialno06.plcpointAddress, wcsTask.serialNo.ToString(), this.serialno06.plcpointLength.ToString()); + Console.WriteLine(DateTime.Now + ":提升机下发" + wcsTask.fromFloorNo + "楼入库指令"); + _logger.Info("提升机下发" + wcsTask.fromFloorNo + "楼入库指令"); + transaction.Commit(); + } + else//当前楼层和起始楼层不一致 + { + wcsTask.taskStatus = 1; + wcsTask.updateBy = "提升机线程"; + wcsTask.updateTime = DateTime.Now; + wcsTask.remark = "提升机任务执行中"; + dbContext.Update(wcsTask); + dbContext.WcsTaskLog.Where(t => t.objid == wcsTask.objid).Update(t => new WcsTaskLog { taskStatus = 1, updateBy = "提升机线程", updateTime = DateTime.Now, remark = "提升机任务执行中" }); + lineEquip.equipStatus = 1; + dbContext.Update(lineEquip); + dbContext.SaveChanges(); + StaticData.PlcDic[0].WriteToPoint(this.targetfloor06.plcpointAddress, wcsTask.fromFloorNo.ToString(), this.targetfloor06.plcpointLength.ToString());//目的地楼层 + StaticData.PlcDic[0].WriteToPoint(this.serialno06.plcpointAddress, wcsTask.serialNo.ToString(), this.serialno06.plcpointLength.ToString()); + Console.WriteLine(DateTime.Now + ":提升机下发去往" + wcsTask.fromFloorNo + "楼指令"); + _logger.Info("提升机下发去往" + wcsTask.fromFloorNo + "楼指令"); + transaction.Commit(); + } + } + } + if (wcsTask.taskStatus == 1 && Convert.ToInt32(reserialno06) == wcsTask.serialNo) + { + BasePlcpoint floorPoint = StaticData.BasePlcpointList.First(t => t.plcpointNo == "RFID00" + wcsTask.fromFloorNo); + string? rfid = StaticData.PlcDic[0].ReadRFID(floorPoint.plcpointAddress); + _logger.Info($"{wcsTask.fromFloorNo}楼RFID?{rfid},任务RFID{wcsTask.containerNo}"); + if (wcsTask.containerNo == rfid || (string.IsNullOrEmpty(wcsTask.containerNo) && wcsTask.qty > 1)) + { + if (Convert.ToInt32(currentfloor06Value) == wcsTask.fromFloorNo)//提升机当前楼层为初始地楼层 + { + wcsTask.taskStatus = 2; + wcsTask.updateBy = "提升机线程"; + wcsTask.updateTime = DateTime.Now; + wcsTask.remark = "提升机任务执行中"; + BasePlcpoint basePlcpoint = StaticData.BasePlcpointList.First(t => t.floorNo == wcsTask.fromFloorNo && t.plcpointNo.Contains("wcsrun")); + dbContext.Update(wcsTask); + dbContext.WcsTaskLog.Where(t => t.objid == wcsTask.objid).Update(t => new WcsTaskLog { taskStatus = 2, updateBy = "提升机线程", updateTime = DateTime.Now, remark = "提升机任务执行中" }); + dbContext.SaveChanges(); + StaticData.PlcDic[0].WriteToPoint(basePlcpoint.plcpointAddress, "1", basePlcpoint.plcpointLength.ToString()); + StaticData.PlcDic[0].WriteToPoint(this.serialno06.plcpointAddress, wcsTask.serialNo.ToString(), this.serialno06.plcpointLength.ToString()); + Console.WriteLine(DateTime.Now + ":提升机下发" + wcsTask.fromFloorNo + "楼入库指令"); + _logger.Info("提升机下发" + wcsTask.fromFloorNo + "楼入库指令"); + transaction.Commit(); + } + } + } + if (wcsTask.taskStatus == 2 && Convert.ToInt32(reserialno06) == wcsTask.serialNo) + { + if (Convert.ToInt32(hoisterTrayIn06Value) == 1)//托盘已经进提升机 + { + wcsTask.taskStatus = 3; + wcsTask.updateBy = "提升机线程"; + wcsTask.updateTime = DateTime.Now; + wcsTask.remark = "提升机任务执行完成"; + dbContext.Update(wcsTask); + dbContext.WcsTaskLog.Where(t => t.objid == wcsTask.objid).Update(t => new WcsTaskLog { taskStatus = 3, updateBy = "提升机线程", updateTime = DateTime.Now, remark = "提升机任务执行完成" }); + dbContext.SaveChanges(); + StaticData.PlcDic[0].WriteToPoint(this.targetfloor06.plcpointAddress, wcsTask.floorNo.ToString(), this.targetfloor06.plcpointLength.ToString());//目的地楼层 + Console.WriteLine(DateTime.Now + ":提升机下发去往" + wcsTask.floorNo + "楼目的地指令"); + _logger.Info("提升机下发去往" + wcsTask.floorNo + "楼目的地指令"); + transaction.Commit(); + } + } + if (wcsTask.taskStatus == 3 && Convert.ToInt32(currentfloor06Value) == wcsTask.floorNo && Convert.ToInt32(reserialno06) == wcsTask.serialNo)//任务状态为3,且当前楼层为任务的目的楼层 + { + if (wcsTask.floorNo == 1)//目的楼层是1 + { + bool emptyStatus = ReadEmptyLocation(); + _logger.Info($"一楼托盘库是否有任务?{emptyStatus}"); + if (emptyStatus)//托盘库是否有任务,没有任务返回true + { + var linesignal = StaticData.PlcDic[0].Read(StaticData.BasePlcpointList.First(t => t.plcpointNo == $"linesignal0{wcsTask.floorNo}").plcpointAddress); + _logger.Info($"一楼接驳位外侧是否有东西?{linesignal}"); + if (linesignal != null && Convert.ToInt32(linesignal) == 0)//接驳位外侧没有东西 + { + BasePlcpoint clearPoint = StaticData.BasePlcpointList.First(t => t.plcpointNo == $"clear0{wcsTask.floorNo}"); + var clearValue = StaticData.PlcDic[0].Read(clearPoint.plcpointAddress); + if (clearPoint != null && Convert.ToBoolean(clearValue) == true)//是否有报警 + { + Console.WriteLine(DateTime.Now + ":提升机下发报警消除指令"); + _logger.Info("提升机下发报警消除指令"); + StaticData.PlcDic[0].WriteToPoint(clearPoint.plcpointAddress, false, clearPoint.plcpointLength.ToString());//清除报警 + } + wcsTask.taskStatus = 4; + wcsTask.updateBy = "提升机线程"; + wcsTask.updateTime = DateTime.Now; + wcsTask.remark = "提升机任务执行完成"; + dbContext.Update(wcsTask); + dbContext.WcsTaskLog.Where(t => t.objid == wcsTask.objid).Update(t => new WcsTaskLog { taskStatus = 4, updateBy = "提升机线程", updateTime = DateTime.Now, remark = "提升机任务执行完成" }); + dbContext.SaveChanges(); + BasePlcpoint basePlcpoint = StaticData.BasePlcpointList.First(t => t.floorNo == wcsTask.floorNo && t.plcpointNo.Contains("wcsrun")); + StaticData.PlcDic[0].WriteToPoint(basePlcpoint.plcpointAddress, "2", basePlcpoint.plcpointLength.ToString());//去向为2,表示提升机已到达目的地,让货出去 + Console.WriteLine(DateTime.Now + ":提升机下发" + wcsTask.floorNo + "楼出库指令"); + _logger.Info("提升机下发" + wcsTask.floorNo + "楼出库指令"); + transaction.Commit(); + } + else//接驳位外侧有东西 + { + BasePlcpoint clearPoint = StaticData.BasePlcpointList.First(t => t.plcpointNo == $"clear0{wcsTask.floorNo}"); + var clearValue = StaticData.PlcDic[0].Read(clearPoint.plcpointAddress); + if (clearPoint != null && Convert.ToBoolean(clearValue) == false) + { + warningMsg = $"目的楼层{wcsTask.floorNo}接驳位外侧有东西,货物无法继续出提升机"; + StaticData.PlcDic[0].WriteToPoint(clearPoint.plcpointAddress, true, clearPoint.plcpointLength.ToString()); + } + } + } + else + { + warningMsg = $"一楼托盘库有任务正在执行,等待任务执行完成"; + Console.WriteLine(DateTime.Now + ":一楼托盘库有任务正在执行,等待任务执行完成"); + _logger.Info("一楼托盘库有任务正在执行,等待任务执行完成"); + } + } + else + { + var linesignal = StaticData.PlcDic[0].Read(StaticData.BasePlcpointList.First(t => t.plcpointNo == $"linesignal0{wcsTask.floorNo}").plcpointAddress); + _logger.Info($"{wcsTask.floorNo}楼接驳位外侧是否有东西?{linesignal}"); + if (linesignal != null && Convert.ToInt32(linesignal) == 0) + { + wcsTask.taskStatus = 4; + wcsTask.updateBy = "提升机线程"; + wcsTask.updateTime = DateTime.Now; + wcsTask.remark = "提升机任务执行完成"; + dbContext.Update(wcsTask); + dbContext.WcsTaskLog.Where(t => t.objid == wcsTask.objid).Update(t => new WcsTaskLog { taskStatus = 4, updateBy = "提升机线程", updateTime = DateTime.Now, remark = "提升机任务执行完成" }); + dbContext.SaveChanges(); + BasePlcpoint basePlcpoint = StaticData.BasePlcpointList.First(t => t.floorNo == wcsTask.floorNo && t.plcpointNo.Contains("wcsrun")); + StaticData.PlcDic[0].WriteToPoint(basePlcpoint.plcpointAddress, "2", basePlcpoint.plcpointLength.ToString());//去向为2,表示提升机已到达目的地,让货出去 + Console.WriteLine(DateTime.Now + ":提升机下发" + wcsTask.floorNo + "楼出库指令"); + _logger.Info("提升机下发" + wcsTask.floorNo + "楼出库指令"); + transaction.Commit(); + } + else + { + warningMsg = $"{wcsTask.floorNo}楼接驳位外侧有东西{linesignal}"; + BasePlcpoint basePlcpoint = StaticData.BasePlcpointList.First(t => t.plcpointNo == $"clear0{wcsTask.floorNo}"); + StaticData.PlcDic[0].WriteToPoint(basePlcpoint.plcpointAddress, "1", basePlcpoint.plcpointLength.ToString()); + } + } + } + else if (wcsTask.taskStatus == 4)//提升机任务结束 + { + BasePlcpoint basePlcpoint = StaticData.BasePlcpointList.First(t => t.floorNo == wcsTask.floorNo && t.plcpointNo.Contains("wcsrun")); + var wcsRun = StaticData.PlcDic[0].Read(basePlcpoint.plcpointAddress); + _logger.Info($"{wcsTask.floorNo}楼接驳位任务状态{wcsRun}"); + if (wcsRun != null && Convert.ToInt32(wcsRun) == 0)//判断当前接驳位的任务状态,wcsrrun如果是1代表入库,2是出库,0是空闲 + { + BaseEquip floorEquip = StaticData.BaseEquip.First(t => t.objid == wcsTask.floorNo); + wcsTask.nextPointId = floorEquip.objid; + wcsTask.nextPointNo = floorEquip.equipNo; + wcsTask.taskStatus = 5; + wcsTask.updateBy = "提升机线程"; + wcsTask.updateTime = DateTime.Now; + wcsTask.remark = "提升机任务执行完成"; + lineEquip.equipStatus = 0; + Console.WriteLine(DateTime.Now + ":提升机任务完成" + wcsTask.fromFloorNo + "---" + wcsTask.floorNo + "楼指令"); + _logger.Info("提升机任务完成" + wcsTask.fromFloorNo + "---" + wcsTask.floorNo + "楼指令"); + dbContext.Update(lineEquip); + dbContext.Update(wcsTask); + dbContext.WcsTaskLog.Where(t => t.objid == wcsTask.objid).Update(t => new WcsTaskLog { taskStatus = 5, nextPointId = floorEquip.objid, nextPointNo = floorEquip.equipNo, updateBy = "提升机线程", updateTime = DateTime.Now, remark = "提升机任务执行完成" }); + dbContext.SaveChanges(); + transaction.Commit(); + } + } + Outtpyes.Clear(); + break; + } + else + { + continue; + } + } + } + } + } + else//同步楼层,屏蔽状态 + { + if (currentfloor06Value != null && targetfloor06Value != null) + { + Outtpyes.Add(5); + warningMsg = "MES屏蔽已打开,无法下发任务"; + StaticData.PlcDic[0].WriteToPoint(this.targetfloor06.plcpointAddress, Convert.ToString(currentfloor06Value), this.targetfloor06.plcpointLength.ToString()); + ////控制报警灯闪烁 + //this.hoisterAllLight = StaticData.BasePlcpointList.FirstOrDefault(t => t.plcpointNo == "hoisterAllLight"); + //StaticData.PlcDic[0].Write(this.hoisterAllLight.plcpointAddress, 1); + } + } + transaction.Dispose(); + if (Outtpyes.Count > 0) + { + SystemData.InsertWaringLog(dbContext, WaringType.提升机任务下发异常, warningMsg); + //控制报警灯闪烁 + this.hoisterAllLight = StaticData.BasePlcpointList.FirstOrDefault(t => t.plcpointNo == "hoisterAllLight"); + if (warningMsg!= "MES屏蔽已打开,无法下发任务") //MES屏蔽无需下发清空输送线提示,即报警灯亮 + { + StaticData.PlcDic[0].Write(this.hoisterAllLight.plcpointAddress, 1); ///提升机每层楼报警灯亮 + } + } + else + { + SystemData.DeleteWaringLog(dbContext, WaringType.提升机任务下发异常); + //关闭 控制报警灯闪烁 + this.hoisterAllLight = StaticData.BasePlcpointList.FirstOrDefault(t => t.plcpointNo == "hoisterAllLight"); + StaticData.PlcDic[0].Write(this.hoisterAllLight.plcpointAddress, 0); + } + } + catch (Exception ex) + { + try + { + transaction.Rollback(); + } + catch + { + + } + if (ex is PlcException) + { + + } + else + { + SystemData.InsertWaringLog(dbContext, WaringType.提升机任务下发异常, "提升机任务下发异常"+ex.Message); + _logger.Error(ex.Message + "\n" + ex.StackTrace); + } + } + Thread.Sleep(5000); + } + } + } +} diff --git a/src/Khd.Core.Wcs/Wcs/FiveFloorAGV.cs b/src/Khd.Core.Wcs/Wcs/FiveFloorAGV.cs new file mode 100644 index 0000000..36b5864 --- /dev/null +++ b/src/Khd.Core.Wcs/Wcs/FiveFloorAGV.cs @@ -0,0 +1,1106 @@ +using Khd.Core.Domain.Dto.TaskType; +using Khd.Core.Domain.Dto.waring; +using Khd.Core.Domain.Dto.webapi; +using Khd.Core.Domain.Models; +using Khd.Core.EntityFramework; +using Khd.Core.Library; +using Khd.Core.Library.Mapper; +using Khd.Core.Plc.S7; +using Khd.Core.Wcs.Global; +using Masuit.Tools; +using Microsoft.AspNetCore.Razor.Language; +using Microsoft.EntityFrameworkCore; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; +using Newtonsoft.Json; +using Z.EntityFramework.Plus; + +namespace Khd.Core.Wcs.Wcs +{ + /// + /// 五楼AGV调度 + /// + public class FiveFloorAGV + { + private readonly LoggerUtils _logger = new LoggerUtils(); + private readonly IHost _host; + private readonly BasePlcpoint LineSignal; + int FloorNo { get; set; } + int agvID = 28; + public FiveFloorAGV(IHost host, int floor) + { + this._host = host; + FloorNo = floor; + this.LineSignal = StaticData.BasePlcpointList.First(t => t.plcpointNo == "linesignal05"); + } + /// + /// 启动上件扫描监听 + /// + public void StartPoint() + { + Thread FlowPointThread = new(MonitorInLocatorPoint); + FlowPointThread.IsBackground = true; + FlowPointThread.Name = "FiveFloorAGV"; + FlowPointThread.Start(); + Console.WriteLine(DateTime.Now + ":五楼AGV上件扫描监听启动成功"); + _logger.Info("五楼AGV上件扫描监听启动成功"); + } + + public void MonitorInLocatorPoint() + { + using var scope = _host.Services.CreateScope(); + using var dbContext = scope.ServiceProvider.GetRequiredService(); + BaseEquip baseEquip = StaticData.BaseEquip.First(t => t.objid == agvID); + while (true) + { + try + { + dbContext.ChangeTracker.Clear(); + var taskList = dbContext.WcsTask + .Where(t => t.useFlag == 1) + .Where(t => t.IsDelete == 0 || t.IsDelete == null) + .Where(t => t.nextPointId == agvID).OrderBy(t => t.createTime).ToList(); + foreach (var item in taskList) + { + if (taskList.Where(t => t.taskStatus > 0).Where(t => t.objid != item.objid).Any()) + { + _logger.Info($"5楼AGV线程:有其他任务正在执行,跳过当前任务{item.objid}"); + continue; + } + item.updateTime = DateTime.Now; + if (item.taskStatus == 0)//下发任务 + { + BaseDictionary baseDictionary = StaticData.BaseDictionary.First(t => t.objid == item.taskType); + if (item.taskType == StaticTaskType.FiveProductOut)//出库任务 + { + BaseEquip lineEquip = dbContext.BaseEquip.First(t => t.objid == 5); + if (lineEquip.equipStatus == 0) + { + bool canSend = dbContext.WcsTask.Where(t => t.nextPointId == lineEquip.objid && t.taskStatus > 0).Any(); + if (lineEquip.equipStatus == 1) + { + _logger.Info("五楼AGV:接驳位有任务,无法下发出库任务"); + continue; + } + if (Convert.ToInt32(StaticData.PlcDic[0].Read(LineSignal.plcpointAddress)) == 1 && !canSend) + { + Console.WriteLine($"{DateTime.Now}:5楼接驳位上有货,无法下发Agv出库任务"); + continue; + } + BaseEquip nextEquip = StaticData.BaseEquip.First(t => t.floorNo == 5 && t.equipType == 1); + RequestAGVTaskDto agvTask = new() + { + reqCode = StaticData.SnowId.NextId().ToString(), + positionCodePath = new List + { + new () + { + positionCode=item.currPointNo, + type="00" + }, + new () + { + positionCode=nextEquip.agvPositionCode, + type="00" + } + }, + taskTyp = baseDictionary.dicValue, + ctnrTyp = "2" + }; + + string message = JsonConvert.SerializeObject(agvTask); + string result = HttpHelper.SendPostMessage(baseEquip.serverIp, baseEquip.serverPort.Value, "rcms/services/rest/hikRpcService/genAgvSchedulingTask", message); + var reponseMessage = JsonConvert.DeserializeObject(result); + if (reponseMessage != null && reponseMessage.message == "成功") + { + _logger.Info("五楼Agv下发任务成功:" + message); + Console.WriteLine(DateTime.Now + ":五楼Agv下发任务成功:" + item.currPointNo + "," + nextEquip.agvPositionCode); + item.taskCode = reponseMessage.data; + item.taskStatus = 1; + lineEquip.equipStatus = 1; + dbContext.Update(lineEquip); + dbContext.Update(item); + dbContext.WcsTaskLog.Where(t => t.objid == item.objid).Update(t => new WcsTaskLog { taskStatus = 1 }); + dbContext.SaveChanges(); + } + else + { + _logger.Info("五楼Agv下发任务失败" + item.taskType + result); + } + + } + else + { + continue; + } + } + else if (item.taskType == StaticTaskType.FiveStockReturnTask)//退库任务 + { + BaseEquip lineEquip = dbContext.BaseEquip.First(t => t.objid == 5); + if (lineEquip.equipStatus == 0) + { + bool canSend = dbContext.WcsTask.Where(t => t.nextPointId == lineEquip.objid && t.taskStatus > 0).Any(); + if (lineEquip.equipStatus == 1) + { + _logger.Info("五楼AGV:接驳位有任务,无法下发出库任务"); + continue; + } + if (Convert.ToInt32(StaticData.PlcDic[0].Read(LineSignal.plcpointAddress)) == 1 && !canSend) + { + Console.WriteLine($"{DateTime.Now}:5楼接驳位上有货,无法下发Agv出库任务"); + continue; + } + BaseEquip nextEquip = StaticData.BaseEquip.First(t => t.floorNo == 5 && t.equipType == 1); + RequestAGVTaskDto agvTask = new() + { + reqCode = StaticData.SnowId.NextId().ToString(), + positionCodePath = new List + { + new () + { + positionCode=item.currPointNo, + type="00" + }, + new () + { + positionCode=nextEquip.agvPositionCode, + type="00" + } + }, + taskTyp = baseDictionary.dicValue, + ctnrTyp = "2" + }; + + string message = JsonConvert.SerializeObject(agvTask); + string result = HttpHelper.SendPostMessage(baseEquip.serverIp, baseEquip.serverPort.Value, "rcms/services/rest/hikRpcService/genAgvSchedulingTask", message); + var reponseMessage = JsonConvert.DeserializeObject(result); + if (reponseMessage != null && reponseMessage.message == "成功") + { + _logger.Info("五楼Agv下发任务成功:" + message); + Console.WriteLine(DateTime.Now + ":五楼Agv下发任务成功:" + item.currPointNo + "," + nextEquip.agvPositionCode); + item.taskCode = reponseMessage.data; + item.taskStatus = 1; + lineEquip.equipStatus = 1; + dbContext.Update(lineEquip); + dbContext.Update(item); + dbContext.WcsTaskLog.Where(t => t.objid == item.objid).Update(t => new WcsTaskLog { taskStatus = 1 }); + dbContext.SaveChanges(); + } + else + { + _logger.Info("五楼Agv下发任务失败" + item.taskType + result); + } + + } + else + { + continue; + } + } + else if (item.taskType == StaticTaskType.FiveRawToBack)//原材料到背板安装 + { + BaseEquip endEquip = StaticData.BaseEquip.First(t => t.objid == 30); + RequestAGVTaskDto agvTask = new() + { + reqCode = StaticData.SnowId.NextId().ToString(), + positionCodePath = new List + { + new () + { + positionCode=item.currPointNo, + type="00" + }, + new () + { + positionCode= endEquip.agvPositionCode, + type="00" + } + }, + taskTyp = baseDictionary.dicValue, + ctnrTyp = "2" + }; + string message = JsonConvert.SerializeObject(agvTask); + string result = HttpHelper.SendPostMessage(baseEquip.serverIp, baseEquip.serverPort.Value, "rcms/services/rest/hikRpcService/genAgvSchedulingTask", message); + var reponseMessage = JsonConvert.DeserializeObject(result); + if (reponseMessage != null && reponseMessage.message == "成功") + { + _logger.Info("五楼Agv下发任务成功:" + message); + Console.WriteLine(DateTime.Now + ":五楼Agv下发任务成功:" + item.currPointNo + "," + endEquip.agvPositionCode); + item.taskCode = reponseMessage.data; + item.taskStatus = 1; + dbContext.Update(item); + dbContext.WcsTaskLog.Where(t => t.objid == item.objid).Update(t => new WcsTaskLog { taskStatus = 1 }); + dbContext.SaveChanges(); + } + else + { + _logger.Info("五楼Agv下发任务失败" + item.taskType + result); + } + } + else if (item.taskType == StaticTaskType.FiveHalfIn)//背板安装到半成品 + { + BaseEquip currentEquip = StaticData.BaseEquip.First(t => t.objid == 30); + var agvTask = new RequestAGVTaskDto + { + reqCode = StaticData.SnowId.NextId().ToString(), + positionCodePath = new List + { + new () + { + positionCode=currentEquip.agvPositionCode, + type="00" + }, + new () + { + positionCode=item.endPointNo, + type="00" + } + }, + taskTyp = baseDictionary.dicValue, + ctnrTyp = "2", + }; + string message = JsonConvert.SerializeObject(agvTask); + string result = HttpHelper.SendPostMessage(baseEquip.serverIp, baseEquip.serverPort.Value, "rcms/services/rest/hikRpcService/genAgvSchedulingTask", message); + var reponseMessage = JsonConvert.DeserializeObject(result); + if (reponseMessage != null && reponseMessage.message == "成功") + { + _logger.Info("五楼Agv下发任务成功:" + message); + Console.WriteLine(DateTime.Now + ":五楼Agv下发任务成功:" + currentEquip.agvPositionCode + "," + item.endPointNo); + item.taskCode = reponseMessage.data; + item.taskStatus = 1; + dbContext.Update(item); + dbContext.WcsTaskLog.Where(t => t.objid == item.objid).Update(t => new WcsTaskLog() { taskStatus = 1 }); + dbContext.SaveChanges(); + } + else + { + _logger.Info("五楼Agv下发任务失败" + item.taskType + result); + } + } + else if (item.taskType == StaticTaskType.FiveRawToSplit)//原材料到拆分区 + { + BaseEquip currentEquip = StaticData.BaseEquip.First(t => t.objid == 29); + RequestAGVTaskDto agvTask = new() + { + reqCode = StaticData.SnowId.NextId().ToString(), + positionCodePath = new List + { + new () + { + positionCode=item.currPointNo, + type="00" + }, + new () + { + positionCode=currentEquip.agvPositionCode, + type="00" + } + }, + taskTyp = baseDictionary.dicValue, + ctnrTyp = "2" + }; + string message = JsonConvert.SerializeObject(agvTask); + string result = HttpHelper.SendPostMessage(baseEquip.serverIp, baseEquip.serverPort.Value, "rcms/services/rest/hikRpcService/genAgvSchedulingTask", message); + var reponseMessage = JsonConvert.DeserializeObject(result); + if (reponseMessage != null && reponseMessage.message == "成功") + { + _logger.Info("五楼Agv下发任务成功:" + message); + Console.WriteLine(DateTime.Now + ":五楼Agv下发任务成功:" + item.currPointNo + "," + currentEquip.agvPositionCode); + item.taskCode = reponseMessage.data; + item.taskStatus = 1; + dbContext.Update(item); + dbContext.WcsTaskLog.Where(t => t.objid == item.objid).Update(t => new WcsTaskLog { taskStatus = 1 }); + dbContext.SaveChanges(); + } + else + { + _logger.Info("五楼Agv下发任务失败" + item.taskType + result); + } + } + else if (item.taskType == StaticTaskType.FiveRawSplitReturn)//拆分区返库 + { + BaseEquip currentEquip = StaticData.BaseEquip.First(t => t.objid == 29); + RequestAGVTaskDto agvTask = new() + { + reqCode = StaticData.SnowId.NextId().ToString(), + positionCodePath = new List + { + new() + { + positionCode = currentEquip.agvPositionCode, + type = "00" + }, + new() + { + positionCode = item.endPointNo, + type = "00" + } + }, + taskTyp = baseDictionary.dicValue, + ctnrTyp = "2" + + }; + string message = JsonConvert.SerializeObject(agvTask); + string result = HttpHelper.SendPostMessage(baseEquip.serverIp, baseEquip.serverPort.Value, "rcms/services/rest/hikRpcService/genAgvSchedulingTask", message); + var reponseMessage = JsonConvert.DeserializeObject(result); + if (reponseMessage != null && reponseMessage.message == "成功") + { + _logger.Info("五楼Agv下发任务成功:" + message); + Console.WriteLine(DateTime.Now + ":五楼Agv下发任务成功:" + currentEquip.agvPositionCode + "," + item.endPointNo); + item.taskCode = reponseMessage.data; + item.taskStatus = 1; + dbContext.Update(item); + dbContext.WcsTaskLog.Where(t => t.objid == item.objid).Update(t => new WcsTaskLog { taskStatus = 1 }); + dbContext.SaveChanges(); + } + else + { + _logger.Info("五楼Agv下发任务失败" + item.taskType + result); + } + } + else if (item.taskType == StaticTaskType.FiveRawIn)//原材料入库 + { + BaseEquip startEquip = StaticData.BaseEquip.First(t => t.objid == 5); + var agvTask = new RequestAGVTaskDto + { + reqCode = StaticData.SnowId.NextId().ToString(), + positionCodePath = new List + { + new () + { + positionCode= startEquip.agvPositionCode, + type="00" + }, + new () + { + positionCode=item.endPointNo, + type="00" + } + }, + taskTyp = baseDictionary.dicValue, + ctnrTyp = "2", + }; + string message = JsonConvert.SerializeObject(agvTask); + string result = HttpHelper.SendPostMessage(baseEquip.serverIp, baseEquip.serverPort.Value, "rcms/services/rest/hikRpcService/genAgvSchedulingTask", message); + var reponseMessage = JsonConvert.DeserializeObject(result); + if (reponseMessage != null && reponseMessage.message == "成功") + { + _logger.Info("五楼Agv下发任务成功:" + message); + Console.WriteLine(DateTime.Now + ":五楼Agv下发任务成功:" + startEquip.agvPositionCode + "," + item.endPointNo); + item.taskCode = reponseMessage.data; + item.taskStatus = 1; + dbContext.Update(item); + dbContext.WcsTaskLog.Where(t => t.objid == item.objid).Update(t => new WcsTaskLog() { taskStatus = 1 }); + dbContext.SaveChanges(); + } + else + { + _logger.Info("五楼Agv下发任务失败" + item.taskType + result); + } + } + else if (item.taskType == StaticTaskType.FiveRemove)//移库 + { + var agvTask = new RequestAGVTaskDto + { + reqCode = StaticData.SnowId.NextId().ToString(), + positionCodePath = new List + { + new () + { + positionCode=item.currPointNo, + type="00" + }, + new () + { + positionCode=item.endPointNo, + type="00" + } + }, + taskTyp = baseDictionary.dicValue, + ctnrTyp = "2", + }; + string message = JsonConvert.SerializeObject(agvTask); + string result = HttpHelper.SendPostMessage(baseEquip.serverIp, baseEquip.serverPort.Value, "rcms/services/rest/hikRpcService/genAgvSchedulingTask", message); + var reponseMessage = JsonConvert.DeserializeObject(result); + if (reponseMessage != null && reponseMessage.message == "成功") + { + _logger.Info("五楼Agv下发任务成功:" + message); + Console.WriteLine(DateTime.Now + ":五楼Agv下发任务成功:" + item.currPointNo + "," + item.endPointNo); + item.taskCode = reponseMessage.data; + item.taskStatus = 1; + dbContext.Update(item); + dbContext.WcsTaskLog.Where(t => t.objid == item.objid).Update(t => new WcsTaskLog() { taskStatus = 1 }); + dbContext.SaveChanges(); + } + else + { + _logger.Info("五楼Agv下发任务失败" + item.taskType + result); + } + } + } + else + { + if (item.taskStatus == 3) + { + if (item.currPointId == 5) + { + var lineSignalValue = StaticData.PlcDic[0].Read(LineSignal.plcpointAddress); + if (lineSignalValue == null || Convert.ToInt32(lineSignalValue) == 0) + { + Console.WriteLine(DateTime.Now + ":五楼Agv:接驳位为空,无法取货"); + _logger.Info("五楼Agv:接驳位为空,无法取货"); + continue; + } + } + else if (item.endPointId == 5) + { + var lineSignalValue = StaticData.PlcDic[0].Read(LineSignal.plcpointAddress); + var wcsrun = StaticData.PlcDic[0].Read(StaticData.BasePlcpointList.First(t => t.plcpointNo == "wcsrun03").plcpointAddress); + if (lineSignalValue == null || Convert.ToInt32(lineSignalValue) == 1 || wcsrun == null || wcsrun.ToString() != "0") + { + Console.WriteLine(DateTime.Now + ":五楼Agv:接驳位有货,无法送货"); + _logger.Info("五楼Agv:接驳位有货,无法送货"); + continue; + } + } + var agvTask = new RequestAGVTaskDto + { + reqCode = StaticData.SnowId.NextId().ToString(), + taskCode = item.taskCode + }; + string message = JsonConvert.SerializeObject(agvTask); + string result = HttpHelper.SendPostMessage(baseEquip.serverIp, baseEquip.serverPort.Value, "rcms/services/rest/hikRpcService/continueTask", message); + ReponseMessage? reponseMessage = JsonConvert.DeserializeObject(result); + if (reponseMessage != null && reponseMessage.message == "成功") + { + _logger.Info("五楼Agv下发继续任务成功:" + message); + Console.WriteLine(DateTime.Now + ":五楼Agv继续任务:" + item.currPointNo + "," + item.endPointNo); + item.taskStatus = 4; + dbContext.Update(item); + dbContext.WcsTaskLog.Where(t => t.objid == item.objid).Update(t => new WcsTaskLog() { taskStatus = 4 }); + dbContext.SaveChanges(); + } + } + else if (item.taskStatus == 5) + { + if (item.taskType == StaticTaskType.FiveRemove)//移库 + { + Console.WriteLine(DateTime.Now + ":五楼AGV线程完成任务" + item.currPointNo + "," + item.endPointNo); + _logger.Info("五楼Agv完成任务成功:" + item.ToJsonString()); + WmsProductStock? wmsProductStock = null; + var wmsRawStock = dbContext.WmsRawStock.Where(t => t.locationCode == item.currPointNo).FirstOrDefault(); + if (wmsRawStock != null) + { + wmsRawStock.locationCode = item.endPointNo; + dbContext.Update(wmsRawStock); + } + else if (wmsRawStock == null) + { + wmsProductStock = dbContext.WmsProductStock.FirstOrDefault(t => t.locationCode == item.currPointNo); + if (wmsProductStock != null) + { + wmsProductStock.locationCode = item.endPointNo; + dbContext.Update(wmsProductStock); + } + else + { + continue; + } + } + else + { + continue; + } + WmsBaseLocation wmsBaseLocation = dbContext.WmsBaseLocation.Where(t => t.locationId == item.currPointId).First(); + WmsBaseLocation toLocation = dbContext.WmsBaseLocation.Where(t => t.locationId == item.endPointId).First(); + SystemData.UnLockOutLocation(wmsBaseLocation, dbContext); + SystemData.UnLockOutLocation(toLocation, dbContext); + dbContext.WmsBaseLocation.Where(t => t.locationId == wmsBaseLocation.locationId) + .Update(t => new WmsBaseLocation() { containerCode = null, updateTime = DateTime.Now, locationStatus = "1", returnFlag = "0" }); + dbContext.WmsBaseLocation.Where(t => t.locationId == toLocation.locationId) + .Update(t => new WmsBaseLocation { containerCode = item.containerNo, updateTime = DateTime.Now, locationStatus = "1", returnFlag = wmsBaseLocation.returnFlag }); + + //dbContext.WmsBaseLocation.Where(t => t.locationId == item.currPointId).Update(t => new WmsBaseLocation + //{ + // returnFlag = "0", + // locationStatus = "1", + // containerCode = null, + // updateTime = DateTime.Now + //}); + //dbContext.WmsBaseLocation.Where(t => t.locationId == item.endPointId).Update(t => new WmsBaseLocation + //{ + // locationStatus = "1", + // returnFlag = wmsBaseLocation.returnFlag, + // containerCode = item.containerNo, + // updateTime = DateTime.Now + //}); + + dbContext.Remove(item); + dbContext.WcsTaskLog.Where(t => t.objid == item.objid).Update(t => new WcsTaskLog() { taskStatus = 6 }); + #region 插入移库记录 + var wmsMove = dbContext.WmsMove.Where(t => t.MoveId == item.orderId).FirstOrDefault(); + if (wmsMove == null) + { + wmsMove = new WmsMove(); + wmsMove.MoveId = StaticData.SnowId.NextId(); + wmsMove.TaskCode = StaticData.SnowId.NextId().ToString(); + wmsMove.WarehouseId = wmsBaseLocation.warehouseId; + wmsMove.OriLocationCode = wmsBaseLocation.locationCode; + wmsMove.TargetLocationCode = toLocation.locationCode; + wmsMove.InstockBatch = wmsRawStock == null ? wmsProductStock.productBatch : wmsRawStock.instockBatch; + wmsMove.MaterialId = wmsRawStock == null ? wmsProductStock.productId : wmsRawStock.materialId; + wmsMove.PlanAmount = 1; + wmsMove.RealOutstockAmount = 1; + wmsMove.RealInstockAmount = 1; + wmsMove.OperationType = "3"; + wmsMove.MoveWay = "2"; + wmsMove.MoveType = "1"; + wmsMove.AuditStatus = "1"; + wmsMove.ExecuteStatus = "2"; + wmsMove.UpdateBy = "WCS"; + wmsMove.UpdateDate = DateTime.Now; + wmsMove.BeginTime = DateTime.Now; + wmsMove.EndTime = DateTime.Now; + dbContext.WmsMove.Add(wmsMove); + } + else + { + wmsMove.RealOutstockAmount += 1; + wmsMove.EndTime = DateTime.Now; + wmsMove.UpdateDate = DateTime.Now; + wmsMove.UpdateBy = "WCS"; + wmsMove.ExecuteStatus = "2"; + dbContext.Update(wmsMove); + } + WmsMoveDetail wmsMoveDetail = new WmsMoveDetail(); + wmsMoveDetail.MoveId = wmsMove.MoveId; + wmsMoveDetail.MaterialBarcode = wmsMove.InstockBatch; + wmsMoveDetail.InstockBatch = wmsMove.InstockBatch; + wmsMoveDetail.MaterialId = wmsRawStock == null ? (long)wmsProductStock.productId : (long)wmsRawStock.materialId; + wmsMoveDetail.LocationCode = toLocation.locationCode; + wmsMoveDetail.PlanAmount = 1; + wmsMoveDetail.RealInstockAmount = 1; + wmsMoveDetail.RealAmount = 1; + wmsMoveDetail.ExecuteStatus = "2"; + wmsMoveDetail.ExecuteTime = DateTime.Now; + wmsMoveDetail.ExecuteEndTime = DateTime.Now; + wmsMoveDetail.ExecutePerson = "WCS"; + wmsMoveDetail.UpdateBy = "WCS"; + wmsMoveDetail.UpdateDate = DateTime.Now; + + dbContext.WmsMoveDetail.Add(wmsMoveDetail); + #endregion + dbContext.SaveChanges(); + SystemData.SendPlcLocation(wmsBaseLocation); + SystemData.SendPlcLocation(toLocation); + + } + else if (item.taskType == StaticTaskType.FiveProductOut)//出库 + { + Console.WriteLine(DateTime.Now + ":五楼AGV线程完成任务" + item.currPointNo + "," + item.endPointNo); + _logger.Info("五楼Agv完成任务成功:" + item.ToJsonString()); + + var wmsProductOutstock = dbContext.WmsProductOutstock.FirstOrDefault(t => t.productOutstockId == item.orderId); + + if (wmsProductOutstock != null) + { + var wmsBaseLocation = dbContext.WmsBaseLocation.Where(t => t.locationId == item.currPointId).First(); + WmsProductStock wmsProductStock = dbContext.WmsProductStock.First(t => t.locationCode == wmsBaseLocation.locationCode); + + + wmsProductOutstock.outstockQty += 1; + if (wmsProductOutstock.applyQty <= wmsProductOutstock.outstockQty) + { + wmsProductOutstock.endTime = DateTime.Now; + wmsProductOutstock.executeStatus = "2"; + } + + WmsProductOutstockDetail? wmsProductOutstockDetail = dbContext.WmsProductOutstockDetail.FirstOrDefault(x => x.productOutstockId == wmsProductOutstock.productOutstockId && x.locationCode == item.currPointId.ToString()); + if (wmsProductOutstockDetail != null) + { //人工出库,mes会自动插入,wcs只需要更新即可 + wmsProductOutstockDetail.outstockAmount = 1; + wmsProductOutstockDetail.executeStatus = "2"; + wmsProductOutstockDetail.updateDate = DateTime.Now; + wmsProductOutstockDetail.endTime = DateTime.Now; + dbContext.Update(wmsProductOutstockDetail); + } + else + { + wmsProductOutstockDetail = new WmsProductOutstockDetail(); + wmsProductOutstockDetail.productOutstockId = wmsProductOutstock.productOutstockId; + wmsProductOutstockDetail.warehouseId = wmsProductOutstock.warehouseId; + wmsProductOutstockDetail.locationCode = wmsBaseLocation.locationCode; + wmsProductOutstockDetail.productBarcode = wmsProductStock.productBatch; + wmsProductOutstockDetail.productId = wmsProductStock.productId; + wmsProductOutstockDetail.planAmount = wmsProductOutstock.applyQty; + wmsProductOutstockDetail.outstockAmount = wmsProductOutstock.outstockQty; + wmsProductOutstockDetail.executeStatus = "2"; + wmsProductOutstockDetail.updateBy = "WCS"; + wmsProductOutstockDetail.updateDate = DateTime.Now; + wmsProductOutstockDetail.beginTime = DateTime.Now; + wmsProductOutstockDetail.endTime = DateTime.Now; + dbContext.Add(wmsProductOutstockDetail); + } + wmsBaseLocation.locationStatus = "1"; + wmsBaseLocation.containerCode = null; + wmsBaseLocation.updateTime = DateTime.Now; + wmsBaseLocation.updateBy = "WCS"; + + SystemData.UnLockOutLocation(wmsBaseLocation, dbContext); + dbContext.Update(wmsBaseLocation); + dbContext.WmsProductStock.Where(t => t.locationCode == wmsBaseLocation.locationCode).Delete(); + BaseEquip floorLineEquip = StaticData.BaseEquip.First(t => t.equipType == 1 && t.floorNo == 5); + WcsTask newTask = CoreMapper.Map(item); + newTask.createTime = DateTime.Now; + newTask.nextPointId = floorLineEquip.objid; + newTask.nextPointNo = floorLineEquip.equipNo; + newTask.fromFloorNo = 5; + newTask.floorNo = 1; + newTask.taskStatus = 6; + newTask.objid = StaticData.SnowId.NextId(); + dbContext.Remove(item); + dbContext.Add(newTask); + WcsTaskLog wcsTaskLog = CoreMapper.Map(newTask); + dbContext.Add(wcsTaskLog); + dbContext.SaveChanges(); + dbContext.WcsTaskLog.Where(t => t.objid == item.objid).Update(t => new WcsTaskLog { taskStatus = 6 }); + SystemData.SendPlcLocation(wmsBaseLocation); + } + } + else if (item.taskType == StaticTaskType.FiveRawToBack)//原材料到背板安装 + { + Console.WriteLine(DateTime.Now + ":五楼AGV线程完成任务" + item.currPointNo + "," + item.endPointNo); + _logger.Info("五楼Agv完成任务成功:" + item.ToJsonString()); + WmsRawOutstock? wmsRawOutstock = dbContext.WmsRawOutstock.Where(t => t.rawOutstockId == item.orderId).FirstOrDefault(); + + if (wmsRawOutstock != null) + { + + wmsRawOutstock.realOutstockAmount += 1; + wmsRawOutstock.executeStatus = "2"; + wmsRawOutstock.endTime = DateTime.Now; + + WmsBaseLocation wmsBaseLocation = dbContext.WmsBaseLocation.First(t => t.locationId == item.currPointId); + wmsBaseLocation.returnFlag = "0"; + wmsBaseLocation.locationStatus = "1"; + wmsBaseLocation.containerCode = null; + wmsBaseLocation.updateTime = DateTime.Now; + wmsBaseLocation.updateBy = "WCS"; + + WmsRawStock wmsRawStock = dbContext.WmsRawStock.First(t => t.locationCode == wmsBaseLocation.locationCode); + + + WmsRawOutstockDetail newWmsRawOutstockDetail = new WmsRawOutstockDetail(); + newWmsRawOutstockDetail.rawOutstockId = wmsRawOutstock.rawOutstockId; + newWmsRawOutstockDetail.taskCode = wmsRawOutstock.taskCode; + newWmsRawOutstockDetail.warehouseId = wmsRawOutstock.warehouseId; + newWmsRawOutstockDetail.locationCode = wmsRawOutstock.locationCode; + newWmsRawOutstockDetail.materialBarcode = wmsRawOutstock.materialBatch; + newWmsRawOutstockDetail.materialId = wmsRawOutstock.materialId; + MesBaseBarcodeInfo? mesBaseBarcodeInfo = dbContext.MesBaseBarcodeInfo.Where(t => t.barcodeInfo == wmsRawStock.instockBatch).FirstOrDefault(); + if (mesBaseBarcodeInfo != null) + { + newWmsRawOutstockDetail.instockBatch = mesBaseBarcodeInfo.batchCode; + newWmsRawOutstockDetail.materialProductionDate = mesBaseBarcodeInfo.productionDate; + } + newWmsRawOutstockDetail.planAmount = wmsRawOutstock.outstockAmount; + newWmsRawOutstockDetail.outstockAmount = wmsRawOutstock.realOutstockAmount; + newWmsRawOutstockDetail.executeStatus = "2"; + newWmsRawOutstockDetail.outstockPerson = wmsRawOutstock.applyBy; + newWmsRawOutstockDetail.outstockTime = DateTime.Now; + newWmsRawOutstockDetail.outstockWay = "2"; + newWmsRawOutstockDetail.createBy = "WCS"; + newWmsRawOutstockDetail.createDate = DateTime.Now; + newWmsRawOutstockDetail.stackAmount = 1; + + + SystemData.UnLockOutLocation(wmsBaseLocation, dbContext); + dbContext.Add(newWmsRawOutstockDetail); + dbContext.Update(wmsRawOutstock); + dbContext.Update(wmsBaseLocation); + dbContext.WmsRawStock.Where(t => t.locationCode == wmsBaseLocation.locationCode).Delete(); + dbContext.Remove(item); + dbContext.Remove(wmsRawStock); + dbContext.SaveChanges(); + dbContext.WcsTaskLog.Where(t => t.objid == item.objid).Update(t => new WcsTaskLog { taskStatus = 6 }); + SystemData.SendPlcLocation(wmsBaseLocation); + } + } + else if (item.taskType == StaticTaskType.FiveHalfIn)//半成品入库 + { + Console.WriteLine(DateTime.Now + ":五楼AGV线程完成任务" + item.currPointNo + "," + item.endPointNo); + _logger.Info("五楼Agv完成任务成功:" + item.ToJsonString()); + WmsBaseLocation wmsBaseLocation = dbContext.WmsBaseLocation.First(t => t.locationId == item.endPointId); + wmsBaseLocation.locationStatus = "1"; + wmsBaseLocation.containerCode = item.containerNo; + wmsBaseLocation.updateTime = DateTime.Now; + wmsBaseLocation.updateBy = "WCS"; + var mesBasePalletInfo = dbContext.MesBasePalletInfo.Where(t => t.palletInfoCode == item.containerNo).FirstOrDefault(); + var wmsProductInstock = dbContext.WmsProductInstock + .Where(t => t.executeStatus == "1" && t.productType == "2" && t.warehouseId == 521).OrderByDescending(x=>x.applyDate) + .FirstOrDefault(); + if (mesBasePalletInfo != null && wmsProductInstock != null) + { + //WmsProductInstockDetail? wmsProductInstockDetail = dbContext.WmsProductInstockDetail.Where(t => t.productInstockId == wmsProductInstock.productInstockId).FirstOrDefault(); + //if (wmsProductInstockDetail != null) + //{ + wmsProductInstock.executeStatus = "2"; + wmsProductInstock.endTime = DateTime.Now; + dbContext.Update(wmsProductInstock); + WmsProductStock wmsProductStock = new WmsProductStock() + { + productId = wmsProductInstock.productId, + activeFlag = "1", + updateBy = "WCS", + updateDate = DateTime.Now, + saleorderCode = wmsProductInstock.saleorderCode, + saleOrderId = wmsProductInstock.SaleOrderId == null ? 0 : wmsProductInstock.SaleOrderId, + stockType = "2", + productStockId = wmsProductInstock.productInstockId, + qualityStatus = "0", + createBy = "WCS", + createDate = DateTime.Now, + locationCode = wmsBaseLocation.locationCode, + warehouseFloor = 5, + totalAmount = 1, + instockDate = DateTime.Now, + productBatch = mesBasePalletInfo.materialBarcode, + palletInfoCode = mesBasePalletInfo.palletInfoCode, + frozenAmount = 0, + occupyAmount = 0, + planCode = wmsProductInstock.planCode, + planDetailCode = wmsProductInstock.planDetailCode, + warehouseId = 521 + }; + BaseEquip startEquip = StaticData.BaseEquip.First(t => t.objid == item.currPointId); + //wmsProductInstockDetail.executeStatus = "2"; + //wmsProductInstockDetail.instockDate = DateTime.Now; + startEquip.emptyCount = 0; + //dbContext.Update(wmsProductInstockDetail); + dbContext.Update(startEquip); + dbContext.Add(wmsProductStock); + dbContext.Update(wmsBaseLocation); + dbContext.Remove(item); + dbContext.WcsTaskLog.Where(t => t.objid == item.objid).Update(t => new WcsTaskLog { taskStatus = 6 }); + dbContext.SaveChanges(); + //} + SystemData.SendPlcLocation(wmsBaseLocation); + } + } + else if (item.taskType == StaticTaskType.FiveRawToSplit)//原材料到柜体拆分 + { + Console.WriteLine(DateTime.Now + ":五楼AGV线程完成任务" + item.currPointNo + "," + item.endPointNo); + _logger.Info("五楼Agv完成任务成功:" + item.ToJsonString()); + var wmsRawOutStock = dbContext.WmsRawOutstock.Where(t => t.rawOutstockId == item.orderId).FirstOrDefault(); + + WmsBaseLocation wmsBaseLocation = dbContext.WmsBaseLocation.First(t => t.locationId == item.currPointId); + WmsRawStock? wmsRawStock = dbContext.WmsRawStock.Where(t => t.locationCode == wmsBaseLocation.locationCode).FirstOrDefault(); + + if (wmsRawOutStock != null && wmsRawStock != null) + { + + + wmsRawOutStock.realOutstockAmount += 1; + wmsRawOutStock.executeStatus = "2"; + wmsRawOutStock.endTime = DateTime.Now; + + + + WmsRawOutstockDetail newWmsRawOutstockDetail = new WmsRawOutstockDetail(); + newWmsRawOutstockDetail.rawOutstockId = wmsRawOutStock.rawOutstockId; + newWmsRawOutstockDetail.taskCode = wmsRawOutStock.taskCode; + newWmsRawOutstockDetail.warehouseId = wmsRawOutStock.warehouseId; + newWmsRawOutstockDetail.locationCode = wmsRawStock.locationCode; + newWmsRawOutstockDetail.materialBarcode = wmsRawStock.instockBatch; + newWmsRawOutstockDetail.materialId = wmsRawStock.materialId; + MesBaseBarcodeInfo? mesBaseBarcodeInfo = dbContext.MesBaseBarcodeInfo.Where(t => t.barcodeInfo == wmsRawStock.instockBatch).FirstOrDefault(); + if (mesBaseBarcodeInfo != null) + { + newWmsRawOutstockDetail.instockBatch = mesBaseBarcodeInfo.batchCode; + newWmsRawOutstockDetail.materialProductionDate = mesBaseBarcodeInfo.productionDate; + } + newWmsRawOutstockDetail.planAmount = wmsRawOutStock.outstockAmount; + newWmsRawOutstockDetail.outstockAmount = wmsRawOutStock.realOutstockAmount; + newWmsRawOutstockDetail.executeStatus = "2"; + newWmsRawOutstockDetail.outstockPerson = wmsRawOutStock.applyBy; + newWmsRawOutstockDetail.outstockTime = DateTime.Now; + newWmsRawOutstockDetail.outstockWay = "2"; + newWmsRawOutstockDetail.createBy = "WCS"; + newWmsRawOutstockDetail.createDate = DateTime.Now; + newWmsRawOutstockDetail.stackAmount = 1; + + + + wmsBaseLocation.locationStatus = "1"; + wmsBaseLocation.containerCode = null; + wmsBaseLocation.updateTime = DateTime.Now; + wmsBaseLocation.updateBy = "WCS"; + SystemData.UnLockOutLocation(wmsBaseLocation, dbContext); + dbContext.Update(wmsBaseLocation); + dbContext.Update(wmsRawOutStock); + dbContext.Add(newWmsRawOutstockDetail); + dbContext.Remove(wmsRawStock); + dbContext.Remove(item); + dbContext.SaveChanges(); + dbContext.WcsTaskLog.Where(t => t.objid == item.objid).Update(t => new WcsTaskLog { taskStatus = 6 }); + SystemData.SendPlcLocation(wmsBaseLocation); + } + } + else if (item.taskType == StaticTaskType.FiveRawSplitReturn)//柜体拆分到原材料 + { + Console.WriteLine(DateTime.Now + ":五楼AGV线程完成任务" + item.currPointNo + "," + item.endPointNo); + _logger.Info("五楼Agv完成任务成功:" + item.ToJsonString()); + WmsBaseLocation wmsBaseLocation = dbContext.WmsBaseLocation.First(t => t.locationId == item.endPointId); + wmsBaseLocation.locationStatus = "1"; + wmsBaseLocation.returnFlag = "1"; + wmsBaseLocation.containerCode = item.containerNo; + wmsBaseLocation.updateTime = DateTime.Now; + wmsBaseLocation.updateBy = "WCS"; + MesBasePalletInfo? mesBasePalletInfo = dbContext.MesBasePalletInfo.FirstOrDefault(t => t.palletInfoCode == item.containerNo); + if (mesBasePalletInfo != null) + { + MesBaseBarcodeInfo? mesBaseBarcodeInfo = dbContext.MesBaseBarcodeInfo.FirstOrDefault(t => t.barcodeInfo == mesBasePalletInfo.materialBarcode); + if (mesBaseBarcodeInfo != null) + { + WmsRawStock wmsRawStock = new() + { + palletInfoCode = mesBasePalletInfo.palletInfoCode, + activeFlag = "1", + createBy = "WCS", + createDate = DateTime.Now, + frozenAmount = 0, + instockDate = DateTime.Now, + locationCode = wmsBaseLocation.locationCode, + occupyAmount = 0, + warehouseFloor = 5, + stockType = "1", + totalAmount = 1, + saleOrderId = mesBaseBarcodeInfo.saleOrderId == null ? 0 : mesBaseBarcodeInfo.saleOrderId, + safeFlag = mesBaseBarcodeInfo.safeFlag, + supplierId = mesBaseBarcodeInfo.manufacturerId, + materialId = mesBasePalletInfo.materialId, + qualityStatus = "0", + rawStockId = StaticData.SnowId.NextId(), + completeFlag = "0", + instockBatch = mesBaseBarcodeInfo.barcodeInfo, + updateBy = "WCS", + updateDate = DateTime.Now, + warehouseId = 511, + }; + var WmsRawInstock = dbContext.WmsRawInstock.FirstOrDefault(t => t.materialBarCode == mesBasePalletInfo.materialBarcode && (t.instockType == "2" || t.instockType == "4")); + if (WmsRawInstock != null) + { + WmsRawInstock.returnFlag = null; + WmsRawInstock.executeStatus = "2"; + WmsRawInstock.updateDate = DateTime.Now; + + SystemData.UnLockOutLocation(wmsBaseLocation, dbContext); + dbContext.Update(wmsBaseLocation); + dbContext.Update(WmsRawInstock); + dbContext.Add(wmsRawStock); + BaseEquip startEquip = StaticData.BaseEquip.First(t => t.objid == item.currPointId); + startEquip.emptyCount = 0; + dbContext.Update(startEquip); + dbContext.Remove(item); + dbContext.SaveChanges(); + dbContext.WcsTaskLog.Where(t => t.objid == item.objid).Update(t => new WcsTaskLog { taskStatus = 6 }); + SystemData.SendPlcLocation(wmsBaseLocation); + } + } + } + + } + else if (item.taskType == StaticTaskType.FiveRawIn)//原材料入库 + { + Console.WriteLine(DateTime.Now + ":五楼AGV线程完成任务" + item.currPointNo + "," + item.endPointNo); + _logger.Info("五楼Agv完成任务成功:" + item.ToJsonString()); + WmsBaseLocation wmsBaseLocation = dbContext.WmsBaseLocation.First(t => t.locationId == item.endPointId); + wmsBaseLocation.locationStatus = "1"; + wmsBaseLocation.containerCode = item.containerNo; + var mesBasePalletInfo = dbContext.MesBasePalletInfo.FirstOrDefault(t => t.palletInfoCode == item.containerNo); + if (mesBasePalletInfo != null) + { + var mesBaseBarcodeInfo = dbContext.MesBaseBarcodeInfo.FirstOrDefault(t => t.barcodeInfo == mesBasePalletInfo.materialBarcode); + if (mesBaseBarcodeInfo != null) + { + //if (mesBaseBarcodeInfo.PurchaseOrderId == -1) + //{ // 虚拟托盘号,合并的物料分别插入WmsRawInstock + // List mesSaleOrderRelates = dbContext.MesSaleOrderRelate.Where(x => x.SaleOrderId == mesBaseBarcodeInfo.saleOrderId).ToList(); + // List? wmsRawInstocks = new List(); + // foreach (var mesSaleOrderRelate in mesSaleOrderRelates) + // { + // WmsRawInstock wmsRawInstock = new WmsRawInstock() + // { + // taskCode = StaticData.SnowId.NextId().ToString(), + // materialBarCode = null, + // materialBatchCode = null, + // applyBy = "wcs", + // applyDate = System.DateTime.Now, + // purchaseOrderId = mesSaleOrderRelate.PurchaseOrderId, + // beginTime = DateTime.Now, + // endTime = DateTime.Now, + // locationCode = wmsBaseLocation.locationCode, + // executeStatus = "2", + // instockAmount = mesSaleOrderRelate.RelateSaleOrderAmount, + // instockType = "1", + + // materialId = mesSaleOrderRelate.MaterialId, + // operationType = "3", + // palletInfoCode = mesBaseBarcodeInfo.palletInfoCode, + // poNo = mesBaseBarcodeInfo.poNo, + // warehouseId = 511 + // }; + // wmsRawInstocks.Add(wmsRawInstock); + // } + // if (wmsRawInstocks.Count > 0) + // { + // dbContext.AddRange(wmsRawInstocks); + // } + //} + //else + { + WmsRawInstock wmsRawInstock = new WmsRawInstock() + { + taskCode = StaticData.SnowId.NextId().ToString(), + materialBarCode = mesBaseBarcodeInfo.barcodeInfo, + materialBatchCode = mesBaseBarcodeInfo.batchCode, + applyBy = "wcs", + applyDate = System.DateTime.Now, + purchaseOrderId = mesBaseBarcodeInfo.PurchaseOrderId, + beginTime = DateTime.Now, + endTime = DateTime.Now, + locationCode = wmsBaseLocation.locationCode, + executeStatus = "2", + instockAmount = 1, + instockType = "4", + materialId = mesBaseBarcodeInfo.materialId, + operationType = "3", + palletInfoCode = mesBaseBarcodeInfo.palletInfoCode, + poNo = mesBaseBarcodeInfo.poNo, + warehouseId = 511 + }; + dbContext.Add(wmsRawInstock); + + } + + WmsRawStock wmsRawStock = new() + { + palletInfoCode = mesBasePalletInfo.palletInfoCode, + activeFlag = "1", + createBy = "WCS", + createDate = DateTime.Now, + frozenAmount = 0, + instockDate = DateTime.Now, + locationCode = wmsBaseLocation.locationCode, + occupyAmount = 0, + warehouseFloor = 5, + stockType = "1", + totalAmount = 1, + saleOrderId = mesBaseBarcodeInfo.saleOrderId == null ? 0 : mesBaseBarcodeInfo.saleOrderId, + safeFlag = mesBaseBarcodeInfo.safeFlag, + supplierId = mesBaseBarcodeInfo.manufacturerId, + materialId = mesBasePalletInfo.materialId, + qualityStatus = "0", + rawStockId = StaticData.SnowId.NextId(), + completeFlag = mesBaseBarcodeInfo.completeFlag, + instockBatch = mesBaseBarcodeInfo.barcodeInfo, + updateBy = "WCS", + updateDate = DateTime.Now, + warehouseId = 511, + }; + + wmsBaseLocation.returnFlag = "0"; + SystemData.UnLockOutLocation(wmsBaseLocation, dbContext); + dbContext.Update(wmsBaseLocation); + BaseEquip lineEquip = dbContext.BaseEquip.First(t => t.objid == 5); + lineEquip.equipStatus = 0; + dbContext.Update(lineEquip); + dbContext.Add(wmsRawStock); + dbContext.Remove(item); + dbContext.SaveChanges(); + dbContext.WcsTaskLog.Where(t => t.objid == item.objid).Update(t => new WcsTaskLog { taskStatus = 6 }); + SystemData.SendPlcLocation(wmsBaseLocation); + } + } + } + else if (item.taskType == StaticTaskType.FiveStockReturnTask) + { + BaseEquip floorLineEquip = StaticData.BaseEquip.First(t => t.objid == 5); + var wmsRawOutstock = dbContext.WmsRawOutstock.Where(t => t.rawOutstockId == item.orderId).FirstOrDefault(); + var wmsRawStock = dbContext.WmsRawStock.Where(t => t.locationCode == item.currPointNo).FirstOrDefault(); + var wmsBaseLocation = dbContext.WmsBaseLocation.Where(t => t.locationCode == item.currPointNo).FirstOrDefault(); + if (wmsRawOutstock != null && wmsRawStock != null && wmsBaseLocation != null) + { + wmsRawOutstock.realOutstockAmount += 1; + wmsRawOutstock.executeStatus = "2"; + wmsRawOutstock.endTime = DateTime.Now; + dbContext.Remove(wmsRawStock); + wmsBaseLocation.locationStatus = "1"; + wmsBaseLocation.containerCode = null; + wmsBaseLocation.updateTime = DateTime.Now; + wmsBaseLocation.updateBy = "WCS"; + + WmsRawOutstockDetail newWmsRawOutstockDetail = new WmsRawOutstockDetail(); + newWmsRawOutstockDetail.rawOutstockId = wmsRawOutstock.rawOutstockId; + newWmsRawOutstockDetail.taskCode = wmsRawOutstock.taskCode; + newWmsRawOutstockDetail.warehouseId = wmsRawOutstock.warehouseId; + newWmsRawOutstockDetail.locationCode = wmsRawOutstock.locationCode; + newWmsRawOutstockDetail.materialBarcode = wmsRawOutstock.materialBatch; + newWmsRawOutstockDetail.materialId = wmsRawOutstock.materialId; + MesBaseBarcodeInfo? mesBaseBarcodeInfo = dbContext.MesBaseBarcodeInfo.Where(t => t.barcodeInfo == wmsRawStock.instockBatch).FirstOrDefault(); + if (mesBaseBarcodeInfo != null) + { + newWmsRawOutstockDetail.instockBatch = mesBaseBarcodeInfo.batchCode; + newWmsRawOutstockDetail.materialProductionDate = mesBaseBarcodeInfo.productionDate; + } + newWmsRawOutstockDetail.planAmount = wmsRawOutstock.outstockAmount; + newWmsRawOutstockDetail.outstockAmount = wmsRawOutstock.realOutstockAmount; + newWmsRawOutstockDetail.executeStatus = "2"; + newWmsRawOutstockDetail.outstockPerson = wmsRawOutstock.applyBy; + newWmsRawOutstockDetail.outstockTime = DateTime.Now; + newWmsRawOutstockDetail.outstockWay = "2"; + newWmsRawOutstockDetail.createBy = "WCS"; + newWmsRawOutstockDetail.createDate = DateTime.Now; + newWmsRawOutstockDetail.stackAmount = 1; + + + SystemData.UnLockOutLocation(wmsBaseLocation, dbContext); + dbContext.Add(newWmsRawOutstockDetail); + dbContext.Update(wmsBaseLocation); + dbContext.Update(wmsRawOutstock); + item.createTime = DateTime.Now; + item.nextPointId = floorLineEquip.objid; + item.nextPointNo = floorLineEquip.equipNo; + item.fromFloorNo = 5; + item.floorNo = 1; + item.taskStatus = 6; + dbContext.Update(item); + dbContext.WcsTaskLog.Where(t => t.objid == item.objid).Update(t => new WcsTaskLog { taskStatus = 6, updateTime = DateTime.Now }); + dbContext.SaveChanges(); + } + } + } + } + break; + } + } + catch (Exception ex) + { + if (ex is PlcException) + { + + } + else + { + _logger.Error(ex.Message + "\n" + ex.StackTrace); + } + } + finally + { + Thread.Sleep(1000); + } + } + } + + } +} diff --git a/src/Khd.Core.Wcs/Wcs/FiveFloorBearAgv.cs b/src/Khd.Core.Wcs/Wcs/FiveFloorBearAgv.cs new file mode 100644 index 0000000..0116820 --- /dev/null +++ b/src/Khd.Core.Wcs/Wcs/FiveFloorBearAgv.cs @@ -0,0 +1,169 @@ +using Khd.Core.Domain.Dto.webapi; +using Khd.Core.Domain.Models; +using Khd.Core.EntityFramework; +using Khd.Core.Library; +using Khd.Core.Wcs.Global; +using Masuit.Tools; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; +using Newtonsoft.Json; +using Z.EntityFramework.Plus; + +namespace Khd.Core.Wcs.Wcs +{ + /// + /// 背负式AGV + /// + public class FiveFloorBearAgv + { + private readonly LoggerUtils _logger = new LoggerUtils(); + private readonly IHost _host; + int FloorNo { get; set; } + int agvID = 10; + public FiveFloorBearAgv(IHost host, int floor) + { + this._host = host; + FloorNo = floor; + } + /// + /// 启动上件扫描监听 + /// + public void StartPoint() + { + + Thread FlowPointThread = new(MonitorInLocatorPoint); + FlowPointThread.IsBackground = true; + FlowPointThread.Name = "FiveFloorBearAgv"; + FlowPointThread.Start(); + Console.WriteLine(DateTime.Now + ":五楼AGV上件扫描监听启动成功"); + _logger.Info("五楼AGV上件扫描监听启动成功"); + } + + public void MonitorInLocatorPoint() + { + using var scope = _host.Services.CreateScope(); + using var dbContext = scope.ServiceProvider.GetRequiredService(); + List taskType = new() { 1, 3, 5, 7 }; + BaseEquip baseEquip = StaticData.BaseEquip.First(t => t.objid == agvID); + while (true) + { + try + { + dbContext.ChangeTracker.Clear(); + var taskList = dbContext.WcsTask + .Where(t => t.IsDelete == 0 || t.IsDelete == null) + .Where(t => t.nextPointId == agvID) + .OrderBy(t => t.createTime).ToList(); + + foreach (var item in taskList)//出库 + { + item.updateTime = DateTime.Now; + if (item.taskStatus == 0)//下发任务 + { + BaseEquip startEquip = StaticData.BaseEquip.First(t => t.objid == item.currPointId); + BaseEquip endEquip = StaticData.BaseEquip.First(t => t.objid == item.endPointId); + BaseDictionary baseDictionary = dbContext.BaseDictionary.First(t => t.objid == item.taskType); + var agvTask = new RequestAGVTaskDto + { + reqCode = StaticData.SnowId.NextId().ToString(), + positionCodePath = new List + { + new () + { + positionCode=startEquip.agvPositionCode, + type=baseDictionary.agvType + }, + new () + { + positionCode=endEquip.agvPositionCode, + type=baseDictionary.agvType + } + }, + taskTyp = baseDictionary.dicValue, + ctnrTyp = "2", + }; + string message = JsonConvert.SerializeObject(agvTask); + string result = HttpHelper.SendPostMessage(baseEquip.serverIp, baseEquip.serverPort.Value, "rcms/services/rest/hikRpcService/genAgvSchedulingTask", message); + var reponseMessage = JsonConvert.DeserializeObject(result); + if (reponseMessage != null && reponseMessage.code == "0") + { + _logger.Info("五楼背负式AGV线程下发任务" + agvTask.ToJsonString()); + Console.WriteLine(DateTime.Now + ":五楼背负式AGV线程下发任务" + startEquip.agvPositionCode + "," + endEquip.agvPositionCode); + item.taskCode = reponseMessage.data; + item.taskStatus = 1; + dbContext.Update(item); + dbContext.WcsTaskLog.Where(t => t.objid == item.objid).Update(t => new WcsTaskLog() { taskStatus = 1 }); + dbContext.SaveChanges(); + } + else + { + _logger.Info("下发小车任务失败" + result); + } + } + else + { + //if (item.useFlag == 1)//接料位-工位默认为1,工位到接料位需Mes通知 + if (item.taskStatus == 4)//通知捡料完成 + { + var agvTask = new RequestAGVTaskDto + { + reqCode = StaticData.SnowId.NextId().ToString(), + taskCode = item.taskCode + }; + string message = JsonConvert.SerializeObject(agvTask); + string result = HttpHelper.SendPostMessage(baseEquip.serverIp, baseEquip.serverPort.Value, "rcms/services/rest/hikRpcService/continueTask", message); + ReponseMessage? reponseMessage = JsonConvert.DeserializeObject(result); + if (reponseMessage != null && reponseMessage.message == "成功") + { + _logger.Info("五楼背负式AGV线程完成任务" + item.objid); + Console.WriteLine(DateTime.Now + ":五楼背负式AGV线程完成任务" + item.currPointNo + "," + item.endPointNo); + item.taskStatus = 5; + dbContext.Update(item); + dbContext.SaveChanges(); + dbContext.WcsTaskLog.Where(t => t.objid == item.objid).Update(t => new WcsTaskLog() { taskStatus = 5 }); + } + } + else if (item.taskStatus == 7)//通知拿料完成 + { + _logger.Info("五楼背负式AGV线程完成任务" + item.objid); + Console.WriteLine(DateTime.Now + ":五楼背负式AGV线程完成任务" + item.currPointNo + "," + item.endPointNo); + var agvTask = new RequestAGVTaskDto + { + reqCode = StaticData.SnowId.NextId().ToString(), + taskCode = item.taskCode + }; + string message = JsonConvert.SerializeObject(agvTask); + string result = HttpHelper.SendPostMessage(baseEquip.serverIp, baseEquip.serverPort.Value, "rcms/services/rest/hikRpcService/continueTask", message); + ReponseMessage? reponseMessage = JsonConvert.DeserializeObject(result); + if (reponseMessage != null && reponseMessage.message == "成功") + { + if (item.taskType == 48) + { + WmsRawReturn? wmsRawReturn = dbContext.WmsRawReturn.Where(t => t.rawReturnId == item.orderId).FirstOrDefault(); + if (wmsRawReturn != null) + { + wmsRawReturn.executeStatus = "2"; + dbContext.Update(wmsRawReturn); + } + } + dbContext.Remove(item); + dbContext.SaveChanges(); + dbContext.WcsTaskLog.Where(t => t.objid == item.objid).Update(t => new WcsTaskLog() { taskStatus = 8 }); + } + } + } + break; + } + } + catch (Exception ex) + { + _logger.Error(ex.Message + "\n" + ex.StackTrace); + } + finally + { + Thread.Sleep(1000); + } + } + } + } +} diff --git a/src/Khd.Core.Wcs/Wcs/FiveFloorCTU.cs b/src/Khd.Core.Wcs/Wcs/FiveFloorCTU.cs new file mode 100644 index 0000000..2ba2ba9 --- /dev/null +++ b/src/Khd.Core.Wcs/Wcs/FiveFloorCTU.cs @@ -0,0 +1,650 @@ +using Khd.Core.Domain.Dto.TaskType; +using Khd.Core.Domain.Dto.webapi; +using Khd.Core.Domain.Models; +using Khd.Core.EntityFramework; +using Khd.Core.Library; +using Khd.Core.Library.Mapper; +using Khd.Core.Plc.S7; +using Khd.Core.Wcs.Global; +using Masuit.Tools; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; +using Newtonsoft.Json; +using Z.EntityFramework.Plus; + +namespace Khd.Core.Wcs.Wcs +{ + /// + /// 五楼CTU调度 + /// + public class FiveFloorCTU + { + List ScanPoint { get; set; }//点位信息 + private readonly IHost _host; + private readonly LoggerUtils _logger = new LoggerUtils(); + private readonly BasePlcpoint LineRFID; + private readonly BasePlcpoint isarrive; + private readonly BasePlcpoint isput; + private readonly BasePlcpoint canReceive; + private readonly BasePlcpoint ReceiveMaterial; + private readonly BasePlcpoint CtuLineWaring; + int FloorNo { get; set; } + int CTUID = 11; + public FiveFloorCTU(IHost host, int floor) + { + this._host = host; + FloorNo = floor; + this.LineRFID = StaticData.BasePlcpointList.First(t => t.plcpointNo == "RFID5001"); + this.isarrive = StaticData.BasePlcpointList.First(t => t.plcpointNo == "isarrive"); + this.isput = StaticData.BasePlcpointList.First(t => t.plcpointNo == "isput"); + this.canReceive = StaticData.BasePlcpointList.First(t => t.plcpointNo == "canReceive"); + this.ReceiveMaterial = StaticData.BasePlcpointList.First(t => t.plcpointNo == "ReceiveMaterial"); + this.CtuLineWaring = StaticData.BasePlcpointList.First(t => t.plcpointNo == "CTULineWaring"); + } + + /// + /// 启动上件扫描监听 + /// + public void StartPoint() + { + + Thread FlowPointThread = new Thread(MonitorInLocatorPoint); + FlowPointThread.IsBackground = true; + FlowPointThread.Name = "FiveFloorCTU"; + FlowPointThread.Start(); + + Thread FlowCTUInWareThread = new Thread(MonitorInWare); + FlowCTUInWareThread.IsBackground = true; + FlowCTUInWareThread.Name = "FiveFloorCTULine"; + FlowCTUInWareThread.Start(); + + Thread HeartThread = new Thread(HeartLogic); + HeartThread.Start(); + + Console.WriteLine(DateTime.Now + ":五楼CTU上件扫描监听启动"); + _logger.Info("五楼CTU上件扫描监听启动"); + } + + private void HeartLogic(object? obj) + { + BasePlcpoint heartPoint = StaticData.BasePlcpointList.First(t => t.plcpointNo == "CTUHeart"); + bool flag = true; + while (true) + { + try + { + flag = !flag; + StaticData.PlcDic[1].WriteToPoint(heartPoint.plcpointAddress, flag.ToString(), heartPoint.plcpointLength.ToString()); + } + catch + { + + } + Thread.Sleep(1000); + } + } + + private void MonitorInWare(object? obj) + { + using var scope = _host.Services.CreateScope(); + using var dbContext = scope.ServiceProvider.GetRequiredService(); + while (true) + { + try + { + dbContext.ChangeTracker.Clear(); + var rfid = StaticData.PlcDic[1].ReadRFID(LineRFID.plcpointAddress); + var isArrive = StaticData.PlcDic[1].Read(isarrive.plcpointAddress); + var receiveMaterial = StaticData.PlcDic[1].Read(ReceiveMaterial.plcpointAddress); + var waring = StaticData.PlcDic[1].Read(CtuLineWaring.plcpointAddress); + if (rfid != null && isArrive != null && receiveMaterial != null && Convert.ToInt32(receiveMaterial) == 1 && Convert.ToInt32(isArrive) == 1) + { + rfid = rfid[rfid.IndexOf('C')..]; + WcsTask? task = dbContext.WcsTask.FirstOrDefault(t => t.containerNo == rfid); + if (task == null) + { + //根据rfid找到库位 + //生成入库任务 + var wmsBaseLocation = dbContext.WmsBaseLocation.FirstOrDefault(t => t.containerCode == rfid); + if (wmsBaseLocation != null) + { + BaseEquip baseEquip = StaticData.BaseEquip.First(t => t.equipNo == "FL051"); + BaseEquip ctuEquip = StaticData.BaseEquip.First(t => t.objid == 11); + if (wmsBaseLocation != null) + { + var wcsTask = new WcsTask() + { + objid = StaticData.SnowId.NextId(), + currPointId = baseEquip.objid, + currPointNo = baseEquip.agvPositionCode, + nextPointId = ctuEquip.objid, + nextPointNo = ctuEquip.equipNo, + endPointId = wmsBaseLocation.locationId, + endPointNo = wmsBaseLocation.agvPositionCode, + taskType = StaticTaskType.FiveAccessoryIn, + taskStatus = 0, + useFlag = 1, + floorNo = 5, + containerNo = rfid.ToString(), + equipmentNo = baseEquip.equipNo, + createBy = FloorNo + "楼CTU", + createTime = DateTime.Now, + }; + wmsBaseLocation.locationStatus = "2"; + wmsBaseLocation.updateTime = DateTime.Now; + dbContext.Update(wmsBaseLocation); + dbContext.Add(wcsTask); + WcsTaskLog wcsTaskLog = CoreMapper.Map(wcsTask); + dbContext.Add(wcsTaskLog); + dbContext.SaveChanges(); + StaticData.PlcDic[1].WriteToPoint(CtuLineWaring.plcpointAddress, false, CtuLineWaring.plcpointLength.ToString()); + } + } + else + { + //报警 + StaticData.PlcDic[1].WriteToPoint(CtuLineWaring.plcpointAddress, true, CtuLineWaring.plcpointLength.ToString()); + } + } + else + { + if (task.taskType == StaticTaskType.FiveAccessoryOut || task.taskType == StaticTaskType.FiveAccessoryRemove || task.taskType == StaticTaskType.FiveAccessoryStorage) + { + dbContext.WcsTask.Where(t => t.objid == task.objid).Delete(); + #region 暂不使用-因为删除之后ctu无法知道还有几个箱子///如果已经开始入库,还有出库任务,删除出库任务 + //List outTasks = dbContext.WcsTask.Where(t => t.taskType == StaticTaskType.FiveAccessoryOut && t.taskStatus == 6).ToList(); + //if(outTasks!=null && outTasks.Count > 0) + //{ + // dbContext.RemoveRange(outTasks); + //} + #endregion + //根据rfid找到库位 + //生成入库任务 + var wmsBaseLocation = dbContext.WmsBaseLocation.FirstOrDefault(t => t.containerCode == rfid); + if (wmsBaseLocation != null) + { + BaseEquip baseEquip = StaticData.BaseEquip.First(t => t.equipNo == "FL051"); + BaseEquip ctuEquip = StaticData.BaseEquip.First(t => t.objid == 11); + if (wmsBaseLocation != null) + { + var wcsTask = new WcsTask() + { + objid = StaticData.SnowId.NextId(), + currPointId = baseEquip.objid, + currPointNo = baseEquip.agvPositionCode, + nextPointId = ctuEquip.objid, + useFlag = 1, + endPointId = wmsBaseLocation.locationId, + endPointNo = wmsBaseLocation.agvPositionCode, + taskType = StaticTaskType.FiveAccessoryIn, + taskStatus = 0, + floorNo = 5, + containerNo = rfid.ToString(), + equipmentNo = baseEquip.equipNo, + createBy = FloorNo + "楼CTU", + createTime = DateTime.Now, + ud3 = "1"//标记任务是出库任务转为入库任务 + }; + wmsBaseLocation.locationStatus = "2"; + wmsBaseLocation.updateTime = DateTime.Now; + dbContext.Update(wmsBaseLocation); + dbContext.Add(wcsTask); + WcsTaskLog wcsTaskLog = CoreMapper.Map(wcsTask); + dbContext.Add(wcsTaskLog); + dbContext.SaveChanges(); + StaticData.PlcDic[1].WriteToPoint(CtuLineWaring.plcpointAddress, false, CtuLineWaring.plcpointLength.ToString()); + SystemData.SendPlcLocation(wmsBaseLocation); + } + } + } + else if (task.taskType == StaticTaskType.FiveAccessoryStorage)//盘库 + { + WmsInventoryCheck? wmsInventoryCheck = dbContext.WmsInventoryCheck.Where(t => t.InventoryCheckId == task.orderId).FirstOrDefault(); + if (wmsInventoryCheck != null) + { + wmsInventoryCheck.InventoryingAmount = wmsInventoryCheck.InventoryingAmount > 0 ? wmsInventoryCheck.InventoryingAmount - 1 : 0; + wmsInventoryCheck.InventoriedAmount++; + if (wmsInventoryCheck.InventoriedAmount >= wmsInventoryCheck.LocationAmount) + { + wmsInventoryCheck.CheckStatus = "2"; + wmsInventoryCheck.EndTime = DateTime.Now; + } + dbContext.WcsTask.Where(t => t.objid == task.objid).Delete(); + //根据rfid找到库位 + //生成入库任务 + var wmsBaseLocation = dbContext.WmsBaseLocation.FirstOrDefault(t => t.containerCode == rfid); + if (wmsBaseLocation != null) + { + BaseEquip baseEquip = StaticData.BaseEquip.First(t => t.equipNo == "FL051"); + BaseEquip ctuEquip = StaticData.BaseEquip.First(t => t.objid == 11); + if (wmsBaseLocation != null) + { + var wcsTask = new WcsTask() + { + objid = StaticData.SnowId.NextId(), + currPointId = baseEquip.objid, + currPointNo = baseEquip.agvPositionCode, + nextPointId = ctuEquip.objid, + useFlag = 1, + endPointId = wmsBaseLocation.locationId, + endPointNo = wmsBaseLocation.agvPositionCode, + taskType = StaticTaskType.FiveAccessoryIn, + taskStatus = 0, + floorNo = 5, + containerNo = rfid.ToString(), + equipmentNo = baseEquip.equipNo, + createBy = FloorNo + "楼CTU", + createTime = DateTime.Now, + }; + dbContext.Update(wmsInventoryCheck); + wmsBaseLocation.locationStatus = "2"; + wmsBaseLocation.updateTime = DateTime.Now; + dbContext.Update(wmsBaseLocation); + dbContext.Add(wcsTask); + WcsTaskLog wcsTaskLog = CoreMapper.Map(wcsTask); + dbContext.Add(wcsTaskLog); + dbContext.SaveChanges(); + StaticData.PlcDic[1].WriteToPoint(CtuLineWaring.plcpointAddress, false, CtuLineWaring.plcpointLength.ToString()); + SystemData.SendPlcLocation(wmsBaseLocation); + } + } + } + } + } + } + else if (Convert.ToInt32(receiveMaterial) == 1 && Convert.ToInt32(isArrive) == 1 && string.IsNullOrEmpty(rfid)) + { + if (!Convert.ToBoolean(waring)) + { + StaticData.PlcDic[1].WriteToPoint(CtuLineWaring.plcpointAddress, true, CtuLineWaring.plcpointLength.ToString()); + } + } + else + { + StaticData.PlcDic[1].WriteToPoint(CtuLineWaring.plcpointAddress, false, CtuLineWaring.plcpointLength.ToString()); + } + } + catch (Exception ex) + { + if (ex is PlcException) + { + + } + else + { + _logger.Error(ex.Message + "\n" + ex.StackTrace); + } + } + Thread.Sleep(1000); + } + } + + /// + /// 预执行任务下发 + /// + //private void CtuWaitLogic() + //{ + // BaseEquip baseEquip = StaticData.BaseEquip.First(t => t.objid == CTUID); + // BaseEquip Fl051 = StaticData.BaseEquip.First(t => t.objid == 19);//入库输送线 + // while (true) + // { + // try + // { + // while (isWait) + // { + // var waitTask = new + // { + // reqCode = StaticData.SnowId.NextId().ToString(), + // positionCode = "CTU_IN", + // nextTask = 1200 + // }; + // string waitMessage = JsonConvert.SerializeObject(waitTask); + // string waitResult = HttpHelper.SendPostMessage(baseEquip.serverIp, baseEquip.serverPort.Value, "rcms/services/rest/hikRpcService/genPreScheduleTask", waitMessage); + // var waitReponse = JsonConvert.DeserializeObject(waitResult); + // if (waitReponse != null && waitReponse.code == "0") + // { + // isSendWait = true; + // } + // else + // { + // _logger.Info("CTU下发预执行任务失败:\nwaitTask:" + waitMessage + "\nwaitResult:" + waitResult); + // } + // Thread.Sleep(1000 * 60 * 10);//每10分钟重新下发预执行任务 + // } + // isSendWait = false; + // } + // catch (Exception ex) + // { + // _logger.Error(ex.Message + "\n" + ex.StackTrace); + // } + // Thread.Sleep(3000); + // } + //} + + private bool CtuWaitLogic() + { + BaseEquip baseEquip = StaticData.BaseEquip.First(t => t.objid == CTUID); + BaseEquip Fl051 = StaticData.BaseEquip.First(t => t.objid == 19);//入库输送线 + try + { + var waitTask = new + { + reqCode = StaticData.SnowId.NextId().ToString(), + positionCode = "CTU_IN", + nextTask = 120 + }; + string waitMessage = JsonConvert.SerializeObject(waitTask); + string waitResult = HttpHelper.SendPostMessage(baseEquip.serverIp, baseEquip.serverPort.Value, "rcms/services/rest/hikRpcService/genPreScheduleTask", waitMessage); + var waitReponse = JsonConvert.DeserializeObject(waitResult); + if (waitReponse != null && waitReponse.code == "0") + { + return true; + } + else + { + _logger.Info("CTU下发预执行任务失败:\nwaitTask:" + waitMessage + "\nwaitResult:" + waitResult); + } + } + catch (Exception ex) + { + _logger.Error(ex.Message + "\n" + ex.StackTrace); + return false; + } + return false; + } + + /// + /// 监控上件扫描点位 + /// + public void MonitorInLocatorPoint() + { + List taskType = new() { 1, 3, 5, 7 }; + using var scope = _host.Services.CreateScope(); + using var dbContext = scope.ServiceProvider.GetRequiredService(); + BaseEquip baseEquip = StaticData.BaseEquip.First(t => t.objid == CTUID); + while (true) + { + try + { + dbContext.ChangeTracker.Clear(); + var taskList = dbContext.WcsTask + .Where(t => t.useFlag == 1) + .Where(t => t.IsDelete == 0 || t.IsDelete == null) + .Where(t => t.nextPointId == CTUID).OrderByDescending(t => t.ud1).ToList(); + foreach (var item in taskList) + { + item.updateTime = DateTime.Now; + if (item.taskStatus == 0)//CTU会同时生成多个任务,生成就下发? + { + if (item.taskType == StaticTaskType.FiveAccessoryOut || item.taskType == StaticTaskType.FiveAccessoryStorage || item.taskType == StaticTaskType.FiveAccessoryRemove)//出库任务 + { + BaseEquip endEquip = StaticData.BaseEquip.First(t => t.objid == item.endPointId); + WmsBaseLocation wmsBaseLocation = dbContext.WmsBaseLocation.First(t => t.locationId == item.currPointId); + var agvTask = new RequestAGVTaskDto + { + reqCode = StaticData.SnowId.NextId().ToString(), + positionCodePath = new List + { + new() + { + positionCode =wmsBaseLocation.agvPositionCode, + type = "05"//05库位 + }, + new() + { + positionCode = endEquip.agvPositionCode, + type = "00"//设备 + }, + }, + ctnrTyp = "1", + taskTyp = "F504" + }; + string message = JsonConvert.SerializeObject(agvTask); + string result = HttpHelper.SendPostMessage(baseEquip.serverIp, baseEquip.serverPort.Value, "rcms/services/rest/hikRpcService/genAgvSchedulingTask", message); + var reponseMessage = JsonConvert.DeserializeObject(result); + if (reponseMessage != null && reponseMessage.code == "0") + { + _logger.Info("五楼CTU线程开始任务" + item.objid); + Console.WriteLine(DateTime.Now + ":五楼CTU线程开始任务" + item.currPointNo + "," + item.endPointNo); + item.taskCode = reponseMessage.data; + item.taskStatus = 1; + + dbContext.Update(item); + dbContext.WcsTaskLog.Where(t => t.objid == item.objid).Update(t => new WcsTaskLog() { taskStatus = 1 }); + dbContext.SaveChanges(); + } + else + { + _logger.Info("CTU下发出库任务失败:" + reponseMessage?.message); + } + } + else if (item.taskType == StaticTaskType.FiveAccessoryIn)//入库任务 + { + bool haveOut = taskList.Where(t => item.taskType == StaticTaskType.FiveAccessoryOut || item.taskType == StaticTaskType.FiveAccessoryStorage || item.taskType == StaticTaskType.FiveAccessoryRemove).Where(t => t.taskStatus != 6).Any(); + if (!haveOut && CtuWaitLogic()) + { + BaseEquip startEquip = StaticData.BaseEquip.First(t => t.objid == item.currPointId); + WmsBaseLocation wmsBaseLocation = dbContext.WmsBaseLocation.First(t => t.locationId == item.endPointId); + var agvTask = new + { + reqCode = StaticData.SnowId.NextId().ToString(), + positionCodePath = new List + { + new() + { + positionCode = startEquip.agvPositionCode , + type = "05"//设备 + }, + new() + { + positionCode = wmsBaseLocation.agvPositionCode, + type = "05"//库位 + }, + }, + ctnrTyp = "1", + taskTyp = "F503" + }; + string message = JsonConvert.SerializeObject(agvTask); + string result = HttpHelper.SendPostMessage(baseEquip.serverIp, baseEquip.serverPort.Value, "rcms/services/rest/hikRpcService/genAgvSchedulingTask", message); + var reponseMessage = JsonConvert.DeserializeObject(result); + if (reponseMessage != null && reponseMessage.code == "0") + { + _logger.Info("五楼CTU线程开始任务" + item.objid); + Console.WriteLine(DateTime.Now + ":五楼CTU线程开始任务" + item.currPointNo + "," + item.endPointNo); + item.taskCode = reponseMessage.data; + item.taskStatus = 1; + dbContext.WcsTaskLog.Where(t => t.objid == item.objid).Update(t => new WcsTaskLog() { taskStatus = 1 }); + dbContext.Update(item); + lock (SystemData.outStockLock) + { + bool hasTask = dbContext.WcsTask.Where(t => t.nextPointId == 11 && (t.taskType == StaticTaskType.FiveAccessoryOut || t.taskType == StaticTaskType.FiveAccessoryStorage || t.taskType == StaticTaskType.FiveAccessoryRemove) ).Any(); + int taskCount = dbContext.WcsTask.Where(t => t.nextPointId == 11 && t.taskType == StaticTaskType.FiveAccessoryIn).Count(); + if ((!hasTask && item.ud3 == "1") || (taskCount >= 6))//如果CTU当前任务数量很多,取消预执行任务,或者出库的任务都生成了入库任务 + { + ExecuteInTask(baseEquip); + } + } + + dbContext.SaveChanges(); + } + else + { + _logger.Info("CTU下发入库任务失败:" + reponseMessage?.message); + } + } + } + } + else + { + if (item.taskStatus == 3) + { + if (item.taskType == StaticTaskType.FiveAccessoryOut || item.taskType == StaticTaskType.FiveAccessoryStorage || item.taskType == StaticTaskType.FiveAccessoryRemove) + { + var canOut = StaticData.PlcDic[1].Read(isput.plcpointAddress); + if (canOut != null && Convert.ToInt64(canOut) == 0) + { + var agvTask = new + { + reqCode = StaticData.SnowId.NextId().ToString(), + taskCode = item.taskCode, + type = 2 + }; + string message = JsonConvert.SerializeObject(agvTask); + string result = HttpHelper.SendPostMessage(baseEquip.serverIp, baseEquip.serverPort.Value, "rcms/services/rest/hikRpcService/boxApplyPass", message); + ReponseMessage? reponseMessage = JsonConvert.DeserializeObject(result); + if (reponseMessage != null && reponseMessage.code == "0") + { + _logger.Info("五楼AGV线程下发任务" + agvTask.ToJsonString() + "\n" + message); + Console.WriteLine(DateTime.Now + ":五楼CTU线程继续任务" + item.currPointId + "," + item.endPointNo); + dbContext.WcsTask.Where(t => t.objid == item.objid).Update(t => new WcsTask() { taskStatus = 4 }); + dbContext.WcsTaskLog.Where(t => t.objid == item.objid).Update(t => new WcsTaskLog() { taskStatus = 4 }); + } + else + { + _logger.Info("CTU第一次下发继续任务失败:" + reponseMessage?.message); + } + } + } + if (item.taskType == StaticTaskType.FiveAccessoryIn) + { + var agvTask = new + { + reqCode = StaticData.SnowId.NextId().ToString(), + taskCode = item.taskCode, + type = 1 + }; + string message = JsonConvert.SerializeObject(agvTask); + string result = HttpHelper.SendPostMessage(baseEquip.serverIp, baseEquip.serverPort.Value, "rcms/services/rest/hikRpcService/boxApplyPass", message); + ReponseMessage? reponseMessage = JsonConvert.DeserializeObject(result); + if (reponseMessage != null && reponseMessage.code == "0") + { + _logger.Info("五楼CTU线程下发任务" + agvTask.ToJsonString() + "\n" + message); + Console.WriteLine(DateTime.Now + ":五楼CTU线程下发任务" + item.currPointId + "," + item.endPointNo); + dbContext.WcsTask.Where(t => t.objid == item.objid).Update(t => new WcsTask() { taskStatus = 4 }); + dbContext.WcsTaskLog.Where(t => t.objid == item.objid).Update(t => new WcsTaskLog() { taskStatus = 4 }); + dbContext.SaveChanges(); + } + else + { + _logger.Info("CTU第二次下发继续任务失败:" + reponseMessage?.message); + } + } + } + else if (item.taskStatus == 5) + { + _logger.Info("五楼CTU线程完成任务" + item.objid); + Console.WriteLine(DateTime.Now + ":五楼CTU线程完成任务" + item.currPointNo + "," + item.endPointNo); + if (item.taskType == StaticTaskType.FiveAccessoryOut || item.taskType == StaticTaskType.FiveAccessoryStorage || item.taskType == StaticTaskType.FiveAccessoryRemove)//出库任务 + { + WmsRawOutstockDetail? wmsRawOutstockDetail = dbContext.WmsRawOutstockDetail.FirstOrDefault(t => t.taskCode == item.objid.ToString()); + if (wmsRawOutstockDetail != null) + { + wmsRawOutstockDetail.executeStatus = "2"; + wmsRawOutstockDetail.updateDate = DateTime.Now; + dbContext.Update(wmsRawOutstockDetail); + } + WmsBaseLocation wmsBaseLocation = dbContext.WmsBaseLocation + .First(t => t.locationId == item.currPointId && t.warehouseFloor == 5); + wmsBaseLocation.locationStatus = "1"; + wmsBaseLocation.ContainerStatus = "2"; + dbContext.Update(wmsBaseLocation); + dbContext.SaveChanges(); + dbContext.WmsRawOutstockDetail.Where(t => t.locationCode == wmsBaseLocation.locationCode).Update(t => new WmsRawOutstockDetail { executeStatus = "2" }); + dbContext.WcsTask.Where(t => t.objid == item.objid).Update(t => new WcsTask() { taskStatus = 6 }); + dbContext.WcsTaskLog.Where(t => t.objid == item.objid).Update(t => new WcsTaskLog() { taskStatus = 6 }); + int wcsTaskCount = dbContext.WcsTask.Where(t => t.taskType == StaticTaskType.FiveAccessoryOut && t.taskStatus != 6).Count(); + if (wcsTaskCount == 0) + { + StaticData.PlcDic[1].WriteToPoint(this.canReceive.plcpointAddress, "1", this.canReceive.plcpointLength?.ToString()); + } + } + else if (item.taskType == StaticTaskType.FiveAccessoryIn)//入库任务 + { + try + { + WmsBaseLocation wmsBaseLocation = dbContext.WmsBaseLocation + .First(t => t.locationId == item.endPointId && t.warehouseFloor == 5); + wmsBaseLocation.locationStatus = "1"; + wmsBaseLocation.ContainerStatus = "1"; + dbContext.Update(wmsBaseLocation); + dbContext.Remove(item); + dbContext.SaveChanges(); + dbContext.WcsTaskLog.Where(t => t.objid == item.objid).Update(t => new WcsTaskLog() { taskStatus = 6 }); + } + catch (Exception ex) + { + _logger.Error($"入库异常捕捉:{ex.Message}"); + } + } + else if (item.taskType == StaticTaskType.FiveAccessoryStorage || item.taskType == StaticTaskType.FiveAccessoryRemove)//出库任务 + { + WmsBaseLocation wmsBaseLocation = dbContext.WmsBaseLocation + .First(t => t.locationId == item.currPointId && t.warehouseFloor == 5); + wmsBaseLocation.locationStatus = "1"; + wmsBaseLocation.ContainerStatus = "2"; + dbContext.Update(wmsBaseLocation); + dbContext.WcsTask.Where(t => t.objid == item.objid).Update(t => new WcsTask() { taskStatus = 6 }); + dbContext.SaveChanges(); + dbContext.WcsTaskLog.Where(t => t.objid == item.objid).Update(t => new WcsTaskLog() { taskStatus = 6 }); + int wcsTaskCount = dbContext.WcsTask.Where(t => (item.taskType == StaticTaskType.FiveAccessoryOut || item.taskType == StaticTaskType.FiveAccessoryStorage || item.taskType == StaticTaskType.FiveAccessoryRemove) && t.taskStatus != 6).Count(); + if (wcsTaskCount == 0) + { + StaticData.PlcDic[1].WriteToPoint(this.canReceive.plcpointAddress, "1", this.canReceive.plcpointLength?.ToString()); + } + } + } + } + } + } + catch (Exception ex) + { + if (ex is PlcException) + { + + } + else + { + _logger.Error(ex.Message + "\n" + ex.StackTrace); + } + } + finally + { + Thread.Sleep(1000); + } + } + } + + /// + /// 通知CTU取消预执行任务 + /// + /// + /// + private void ExecuteInTask(BaseEquip baseEquip) + { + //while (isWait) + { + var executeTask = new + { + reqCode = StaticData.SnowId.NextId().ToString(), + positionCode = "CTU_IN", + nextTask = -1 + }; + string executeMessage = JsonConvert.SerializeObject(executeTask); + string executeResult = HttpHelper.SendPostMessage(baseEquip.serverIp, baseEquip.serverPort.Value, "rcms/services/rest/hikRpcService/genPreScheduleTask", executeMessage); + var executeReponse = JsonConvert.DeserializeObject(executeResult); + if (executeReponse != null && executeReponse.code == "0") + { + _logger.Info("下发CTU执行入库任务成功"); + } + else + { + _logger.Info("下发CTU执行入库任务失败"); + Console.WriteLine($"{DateTime.Now}:下发CTU执行入库任务失败" + executeReponse?.message); + ExecuteInTask(baseEquip); + Thread.Sleep(1000); + } + } + } + + } +} diff --git a/src/Khd.Core.Wcs/Wcs/FiveFloorPoint.cs b/src/Khd.Core.Wcs/Wcs/FiveFloorPoint.cs new file mode 100644 index 0000000..55d75e8 --- /dev/null +++ b/src/Khd.Core.Wcs/Wcs/FiveFloorPoint.cs @@ -0,0 +1,285 @@ +using Khd.Core.Domain.Dto.TaskType; +using Khd.Core.Domain.Models; +using Khd.Core.EntityFramework; +using Khd.Core.Library; +using Khd.Core.Library.Mapper; +using Khd.Core.Plc.S7; +using Khd.Core.Wcs.Global; +using Masuit.Tools; +using Microsoft.EntityFrameworkCore; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; +using Z.EntityFramework.Plus; + +namespace Khd.Core.Wcs.Wcs +{ + /// + /// 五楼接驳位调度 + /// + public class FiveFloorPoint + { + private readonly IHost _host; + private readonly BasePlcpoint LineRFID; + private readonly BasePlcpoint LineSignal; + private readonly LoggerUtils _logger = new LoggerUtils(); + int FloorNo { get; set; } + string EquipNo = ""; + public FiveFloorPoint(IHost host, int floor) + { + this._host = host; + FloorNo = floor; + this.LineRFID = StaticData.BasePlcpointList.First(t => t.plcpointNo == "RFID005"); + this.LineSignal = StaticData.BasePlcpointList.First(t => t.plcpointNo == "linesignal05"); + + } + /// + /// 启动上件扫描监听 + /// + public void StartPoint() + { + + var FlowPointThread = new Thread(MonitorInLocatorPoint); + FlowPointThread.IsBackground = true; + FlowPointThread.Name = "FiveFloorPoint"; + FlowPointThread.Start(); + Console.WriteLine(DateTime.Now + ":五楼接驳位调度启动成功"); + _logger.Info("五楼接驳位调度启动成功"); + } + + public void MonitorInLocatorPoint() + { + List ITypes = new() { 1, 3, 5, 7 }; + using var scope = _host.Services.CreateScope(); + using var dbContext = scope.ServiceProvider.GetRequiredService(); + List canNotIn = new(); + string lastRFID = string.Empty; + while (true) + { + try + { + dbContext.ChangeTracker.Clear(); + //入库任务 + var rfid = StaticData.PlcDic[0].ReadRFID(LineRFID.plcpointAddress); + var isSignal = StaticData.PlcDic[0].Read(LineSignal.plcpointAddress); + BaseEquip baseEquip = StaticData.BaseEquip.First(t => t.equipType == 1 && t.floorNo == FloorNo); + if (rfid != null && isSignal != null) + { + //正常读到输送线信息 有到位信号,并且有托盘,获取条码信息 + if (Convert.ToInt32(isSignal) == 1)//五楼接驳位 + { + //获取条码信息 + var wcsTask = dbContext.WcsTask.OrderBy(t => t.createTime) + .FirstOrDefault(t => t.containerNo == rfid && t.nextPointId == baseEquip.objid); + if (wcsTask != null) + { + + if (StaticData.BigContainerCodes.Contains(rfid)) + { + if (rfid == lastRFID) + { + continue; + } + MesBasePalletInfo? mesBasePalletInfo = dbContext.MesBasePalletInfo.FirstOrDefault(t => t.palletInfoCode == rfid); + if (mesBasePalletInfo != null) + { + MesBaseBarcodeInfo? mesBaseBarcodeInfo = dbContext.MesBaseBarcodeInfo.Where(t => t.palletInfoCode == rfid).FirstOrDefault(); + if (mesBaseBarcodeInfo != null) + { + mesBaseBarcodeInfo.palletInfoCode = null; + dbContext.Update(mesBaseBarcodeInfo); + } + mesBasePalletInfo.bindAmount = null; + mesBasePalletInfo.bindAmount = null; + mesBasePalletInfo.materialBarcode = null; + mesBasePalletInfo.materialCode = null; + mesBasePalletInfo.materialId = null; + mesBasePalletInfo.materialName = null; + mesBasePalletInfo.updateBy = "WCS"; + mesBasePalletInfo.updateTime = DateTime.Now; + dbContext.Update(mesBasePalletInfo); + dbContext.Remove(wcsTask); + dbContext.WcsTaskLog.Where(t => t.objid == wcsTask.objid).Update(t => new WcsTaskLog { taskStatus = 6 }); + dbContext.SaveChanges(); + lastRFID = rfid; + } + } + else//小托盘 + { + if (wcsTask.taskStatus == 5)//入库,提升机任务是完成状态 + { + lock (SystemData.FiveTaskLock) + { + var wmsBaseLocations = dbContext.WmsBaseLocation.Where(t => t.warehouseFloor == FloorNo) + .Where(t => t.activeFlag == "1") + .Where(t => t.delFlag == "0") + .Where(t => t.locationScrapType == "1") + .Where(t => t.warehouseId == 511) + .Where(t => t.locationStatus == "1") + .ToList(); + if (wmsBaseLocations.Count > 0) + { + MesBasePalletInfo? mesBasePalletInfo = dbContext.MesBasePalletInfo.Where(t => t.palletInfoCode == rfid).FirstOrDefault(); + if (mesBasePalletInfo != null) + { + MesBaseBarcodeInfo? mesBaseBarcodeInfo = dbContext.MesBaseBarcodeInfo.FirstOrDefault(t => t.barcodeInfo == mesBasePalletInfo.materialBarcode); + if (mesBaseBarcodeInfo != null) + { + List containerCodes = wmsBaseLocations + .Where(t => t.locDeep == 1) + .Select(t => t.containerCode).ToList();//深库位的托盘 + containerCodes.RemoveAll(t => string.IsNullOrEmpty(t)); + + + //List wmsRawStocks = dbContext.WmsRawStock + // .Where(t => t.materialId == mesBaseBarcodeInfo.materialId) + // .Where(t => t.saleOrderId == mesBaseBarcodeInfo.saleOrderId) + // .Where(t => t.palletInfoCode != null) + // .Where(t => t.warehouseId == 511) + // .Where(t => containerCodes.Contains(t.palletInfoCode)).ToList(); + + //优先把相同采购订单及批次号的放一块 ==》改为找相同型号及采购订单及批次号的深库位库存 + List wmsRawStocks = (from stock in dbContext.WmsRawStock + join codeInfo in dbContext.MesBaseBarcodeInfo + on stock.instockBatch equals codeInfo.barcodeInfo + where codeInfo.batchCode == mesBaseBarcodeInfo.batchCode + && codeInfo.poNo == mesBaseBarcodeInfo.poNo && stock.materialId == mesBaseBarcodeInfo.materialId && stock.warehouseId == 511 + select stock).ToList(); + + + + var bill = from a in wmsRawStocks + join b in wmsBaseLocations + .Where(t => t.locDeep == 1 && mesBaseBarcodeInfo.completeFlag == "0" ? t.returnFlag == "1" : t.returnFlag == "0") on a.palletInfoCode equals b.containerCode + select new { b };//等于当前任务的物料的托盘的库位信息 + var outBill = from a in bill + from b in wmsBaseLocations + where b.locDeep == 2 + && b.locRow == (a.b.locRow % 2 == 0 ? a.b.locRow - 1 : a.b.locRow + 1) + && a.b.locColumn == b.locColumn + && b.locationStatus == "1" + && string.IsNullOrEmpty(b.containerCode) + select new { a, b };//在上面的基础上获取对应托盘的外侧库位的空库位信息 + if (mesBaseBarcodeInfo.completeFlag == "0") + { + outBill = outBill.OrderByDescending(t => t.b.locColumn).ToList(); + wmsBaseLocations = wmsBaseLocations.OrderByDescending(t => t.locColumn).ToList(); + } + else + { + outBill = outBill.OrderBy(t => t.b.locColumn).ToList(); + wmsBaseLocations = wmsBaseLocations.OrderBy(t => t.locColumn).ToList(); + } + WmsBaseLocation? wmsBaseLocation = null; + wmsBaseLocation ??= outBill.Where(t => !canNotIn.Contains(t.b.locationCode)).FirstOrDefault()?.b;//先找相同物料的外侧库位 + wmsBaseLocation ??= wmsBaseLocations.Where(t => !canNotIn.Contains(t.locationCode)).Where(t => string.IsNullOrEmpty(t.containerCode)).FirstOrDefault(t => t.locDeep == 1);//找不到再找深库位 + wmsBaseLocation ??= wmsBaseLocations.Where(t => !canNotIn.Contains(t.locationCode)).Where(t => string.IsNullOrEmpty(t.containerCode)).FirstOrDefault();//找不到再找任意库位 + //深浅库位问题?库位入库优先级等 + + var AgvEquip = StaticData.BaseEquip.First(t => t.objid == 28);//5楼叉车 + if (wmsBaseLocations.Count > 0 && wmsBaseLocation != null) + { + if (wmsBaseLocation.locDeep == 1) + { + bool hasLocation = wmsBaseLocations + .Where(t => t.locRow == (wmsBaseLocation.locRow % 2 == 1 ? (wmsBaseLocation.locRow + 1) : (wmsBaseLocation.locRow - 1))) + .Where(t => t.locColumn == wmsBaseLocation.locColumn) + .Where(t => !string.IsNullOrEmpty(t.containerCode) || t.locationStatus != "1") + .Any(); + if (hasLocation) + { + canNotIn.Add(wmsBaseLocation.locationCode); + Console.WriteLine(DateTime.Now + $":目标库位{canNotIn.Join(",")}的浅库位库位状态异常,无法入库"); + _logger.Info($"目标库位{canNotIn.Join(",")}的浅库位库位状态异常,无法入库"); + continue; + } + } + WcsTask newTask = CoreMapper.Map(wcsTask); + newTask.taskStatus = 0;//创建状态 + newTask.updateTime = DateTime.Now; + newTask.currPointId = baseEquip.objid; + newTask.currPointNo = baseEquip.equipNo; + newTask.nextPointId = AgvEquip.objid; + newTask.nextPointNo = AgvEquip.equipNo; + newTask.endPointId = wmsBaseLocation.locationId; + newTask.endPointNo = wmsBaseLocation.locationCode; + newTask.objid = StaticData.SnowId.NextId(); + newTask.createTime = DateTime.Now; + newTask.taskType = StaticTaskType.FiveRawIn; + if (newTask.fromFloorNo != 1)//如果不是一楼来的,需要通过接口确认入库(质检通过后,点击继续入库) + { + newTask.useFlag = 0; + } + else + { + newTask.useFlag = 1; + } + wmsBaseLocation.locationStatus = "2"; + dbContext.Update(wmsBaseLocation); + dbContext.Remove(wcsTask); + SystemData.LockOutLocation(wmsBaseLocation, dbContext); + + dbContext.Add(newTask); + WcsTaskLog wcsTaskLog = CoreMapper.Map(newTask); + dbContext.Add(wcsTaskLog); + dbContext.SaveChanges(); + canNotIn.Clear(); + } + else + { + Console.WriteLine(DateTime.Now + ":五楼接驳位调度入库任务,未找到库位"); + _logger.Info("五楼接驳位调度入库任务,未找到库位"); + } + } + } + } + } + } + else if (wcsTask.taskStatus == 6) //出库任务,小车任务是完成状态 + { + BaseEquip nextEquip = StaticData.BaseEquip.First(t => t.equipType == 2);//提升机 + BaseEquip endEquip = StaticData.BaseEquip.First(t => t.objid == 1);//提升机 + dbContext.Remove(wcsTask); + WcsTask newTask = CoreMapper.Map(wcsTask); + newTask.objid = StaticData.SnowId.NextId(); + newTask.serialNo = SystemData.GetSerialNo(dbContext); + newTask.nextPointId = nextEquip.objid; + newTask.nextPointNo = nextEquip.equipNo; + newTask.currPointId = baseEquip.objid; + newTask.currPointNo = baseEquip.equipNo; + newTask.endPointId = endEquip.objid; + newTask.endPointNo = endEquip.equipNo; + newTask.ud1 = 30; + newTask.fromFloorNo = FloorNo; + newTask.taskType = 6;//成品出库 + newTask.floorNo = 1;//出库楼层 + newTask.taskStatus = 0; + newTask.createTime = DateTime.Now; + dbContext.Add(newTask); + WcsTaskLog wcsTaskLog = CoreMapper.Map(newTask); + dbContext.WcsTaskLog.Add(wcsTaskLog); + dbContext.SaveChanges(); + } + } + } + } + } + } + catch (Exception ex) + { + if (ex is PlcException) + { + + } + else + { + _logger.Error(ex.Message + "\n" + ex.StackTrace); + } + } + finally + { + Thread.Sleep(1000); + } + } + } + } +} diff --git a/src/Khd.Core.Wcs/Wcs/FlowPoint.cs b/src/Khd.Core.Wcs/Wcs/FlowPoint.cs new file mode 100644 index 0000000..934342e --- /dev/null +++ b/src/Khd.Core.Wcs/Wcs/FlowPoint.cs @@ -0,0 +1,297 @@ +using AngleSharp.Dom; +using Khd.Core.Domain.Dto.wcs; +using Khd.Core.Domain.Models; +using Khd.Core.EntityFramework; +using Khd.Core.Wcs.Global; +using Masuit.Tools.Logging; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; +using Microsoft.Extensions.Logging; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Khd.Core.Domain.Dto.webapi; + +using Khd.Core.Plc.S7; + +using Khd.Core.Wcs.Wcs; +using System.Data; +using Microsoft.EntityFrameworkCore; +using Z.EntityFramework.Plus; + +namespace Khd.Core.Wcs.Wcs +{ + /// + /// 流转点线程 + /// + public class FlowPoint + { + private readonly IHost _host; + private readonly Plc.S7.Plc _plc; + List ScanPoint { get; set; }//点位信息 + BaseSitenode? sitenode { get; set; }//站台信息 + + NodeSetting? NodeSettingCarNo { get; set; } + NodeSetting? NodeSettingCarState { get; set; } + NodeSetting? NodeSettingCarRun { get; set; } + NodeSetting? NodeSettingWcsState { get; set; } + NodeSetting? NodeSettingWcsSend { get; set; } + Thread FlowPointThread; + public FlowPoint(IHost host, Plc.S7.Plc plc, string siteNo) + { + this._host = host; + this._plc = plc; + //this.ScanPoint = StaticData.NodeSettingList.Where(t => t.siteNo == siteNo).ToList();//加载当前站点所对应的点位 + this.sitenode = StaticData.SiteNodeList.FirstOrDefault(t => t.siteNo == siteNo);//获取当前站台信息 + this.NodeSettingCarNo = this.ScanPoint.FirstOrDefault(t => t.plcpointNo.Contains("carno")); + this.NodeSettingCarState = this.ScanPoint.FirstOrDefault(t => t.plcpointNo.Contains("carstate")); + this.NodeSettingCarRun = this.ScanPoint.FirstOrDefault(t => t.plcpointNo.Contains("carrun")); + this.NodeSettingWcsState = this.ScanPoint.FirstOrDefault(t => t.plcpointNo.Contains("plcsendK")); + this.NodeSettingWcsSend = this.ScanPoint.FirstOrDefault(t => t.plcpointNo.Contains("wcsend")); + try + { + //默认启动,清理plc的上位机写入点位值 + this._plc.Write(NodeSettingCarRun.plcpointAddress, MainCentralControl.QingKongDianWei); + this._plc.Write(NodeSettingWcsSend.plcpointAddress, MainCentralControl.QingKongDianWei); + } + catch (Exception ex) + { + Console.WriteLine("站点" + siteNo + " 初始化数据异常" + ex.Message); + LogManager.Error(ex); + } + } + /// + /// 启动上件扫描监听 + /// + public void StartPoint() + { + + FlowPointThread = new Thread(MonitorInLocatorPoint); + FlowPointThread.Start(); + } + public void MonitorInLocatorPoint() + { + while (true) + { + try + { + //通用逻辑下,根据上件记录表,可区分业务,入库,出库,回库 + //- 入库 - 根据小车任务表,可区分流入哪个站点 + //- 出库 - 根据小车任务表,可区分流入哪个站点 + //- 回库 - 根据小车任务表,可区分流入哪个站点 + //- 特殊逻辑:下一站点多个站点,按多条线缓存数优先进少的; + + var carno = this._plc.Read(NodeSettingCarNo.plcpointAddress); + var carstate = this._plc.Read(NodeSettingCarState.plcpointAddress); + var carrun = this._plc.Read(NodeSettingCarRun.plcpointAddress); + var wcsstate = this._plc.Read(NodeSettingWcsState.plcpointAddress); + var wcsend = this._plc.Read(NodeSettingWcsSend.plcpointAddress); + if (carno != null && carstate != null && carrun != null && wcsstate != null && wcsend != null) + { + //清除点位信息 + if (Convert.ToInt32(carno) == 0 && Convert.ToInt32(wcsend) == 1 && Convert.ToInt32(wcsstate) == 1) + { + if (this.sitenode.siteNo == "K48") + { + continue; + } + this._plc.Write(NodeSettingCarRun.plcpointAddress, MainCentralControl.QingKongDianWei); //清空小车去向点位 + this._plc.Write(NodeSettingWcsSend.plcpointAddress, MainCentralControl.QingKongDianWei); //清空wcs处理完成点位 + } + //正常读到小车信息 + if (Convert.ToInt32(carno) > 0 && Convert.ToInt32(wcsend) == 0 && Convert.ToInt32(wcsstate) == 0 && Convert.ToInt32(carstate) == 1 && Convert.ToInt32(carrun) == 0) + { + var carRun = GetTargetTo(this.sitenode.siteNo, Convert.ToInt32(carno)); + if (string.IsNullOrEmpty(carRun)) + { + if (this.sitenode.siteNo =="K48") + { + continue; + } + Console.WriteLine($" FlowPoint类GetTargetTo方法去向返回{carRun},查看错误日志内容!"); + Thread.Sleep(1000); + continue; + } + var ToInt16carRun = MainCentralControl.getValue("2", carRun); + this._plc.Write(this.NodeSettingCarRun.plcpointAddress, ToInt16carRun);//写入小车去向 + this._plc.Write(this.NodeSettingWcsSend.plcpointAddress, MainCentralControl.WcsChuLiWanCheng);//写入wcs处理完成 + LogManager.Info($"当前时间{DateTime.Now} >>> 挂具:{carno}经过站点:{this.sitenode.siteNo},WCS写入去向:{ToInt16carRun};"); + } + } + } + catch (Exception ex) + { + LogManager.Error(ex); + } + finally + { + Thread.Sleep(1000); + } + } + } + /// + /// 根据上件点,物料号,获取下一点位信息 + /// + /// 交互所属站点 + /// 到位挂具号码 + /// 1:给予PLC去向方法 2:\给予PLC物料信息方法 + /// + public string GetTargetTo(string siteNo, int carno) + { + try + { + using var scope = _host.Services.CreateScope(); + using var dbContext = scope.ServiceProvider.GetRequiredService(); + if (siteNo == "K22") + { + var car_material = GetCarMessage(2, carno); + var flag = GetFlag(1, "UpState"); + if (!string.IsNullOrWhiteSpace(car_material) && (flag == "2" || flag == "1"))//挂具携带物料且上件点闸口正常时逻辑处理 + { + var CarRun = GetCarMessage(1, carno); + return CarRun; + } + else if (string.IsNullOrWhiteSpace(car_material) && flag == "1")//挂具为空且上件点闸口维护损坏时逻辑处理 + { + var CarRun = GetFlag(2, "UpState"); + return CarRun; + } + else if (string.IsNullOrWhiteSpace(car_material) && flag == "2")//空挂具走直通发往一线 + { + #region 代码注释折叠 + //var BaseProductionOrderSplitModelXB1 = dbContext.BaseProductionOrderSplit.Where(t => t.lineCode.Contains("01")).ToList(); + //var BaseProductionOrderSplitModelXB2 = dbContext.BaseProductionOrderSplit.Where(t => t.lineCode.Contains("02")).ToList(); + //int xianbie1shuliang = BaseProductionOrderSplitModelXB1.Count;//线别01的数量 + //int xianbie2shuliang = BaseProductionOrderSplitModelXB2.Count;//线别02的数量 + //if (xianbie1shuliang == 0) + //{ + // return "1"; + //} + //if (xianbie2shuliang == 0) + //{ + // return "2"; + //} + //if (xianbie1shuliang != 0 && xianbie2shuliang != 0)//一线二线同时存在订单时 + //{ + // if (xianbie1shuliang < xianbie2shuliang) + // { + // return "1"; + // } + // else if (xianbie1shuliang > xianbie2shuliang) + // { + // return "2"; + // } + // else//一二线订单数量相等时 + // { + // return "2"; + // } + //} + #endregion + return "1"; + } + else if (car_material == null || flag == null)//某个字段逻辑处理出错后日志输入结果 + { + //if (string.IsNullOrWhiteSpace(car_material)) LogManager.Info($"错误日志输出 >>> 未查找到车辆与订单的绑定信息!"); + //if (string.IsNullOrWhiteSpace(flag)) LogManager.Info($"错误日志输出 >>> 未查找到上件闸口状态信息!"); + return null; + } + } + else if (siteNo == "K18") + { + //dbContext.BaseWaitdownline.Where(t => t.carNo == carno).Update(a => new BaseWaitdownline() { downline = 0 }); //修改车辆状态为未上线 (修改downline字段等于0) + //flag == 2 上件点闸口正常时写弯通2,挂具返回上件点, + //flag == 1上件点闸口人工维护损坏时写直通1,挂具返回K22流转点; + var flag = GetFlag(1, "UpState"); + return flag; + } + else if (siteNo == "K48") //如果是K46发过来的带件车辆逻辑处理 + { + var shifodaijian = GetCarMessage(2, carno); + if (!string.IsNullOrWhiteSpace(shifodaijian)) + { + return "2"; + } + else + { + return ""; + } + } + LogManager.Info("错误日志输出 >>> FlowPoint类GetTargetTo方法未确认返回值,从底部返回NULL!"); + return null; + + /// + /// 联查base_waitdownline 与 base_production_order_split,截取线别字段确定挂具在K22交互点去向 + /// + /// bianbie = 1 查找任务中的线别字段, bianbie = 2 查找车辆、Vin信息 + /// 挂具号 + /// + string GetCarMessage(int bianbie, int CarNo) + { + var listWaitDownLine = dbContext.BaseWaitdownline.Where(t => t.isDelete == 0 && t.carNo == CarNo).ToList(); + var listOrder = dbContext.BaseProductionOrderSplit.Where(t => t.isover == 0).ToList(); + var resultList = (from waitdownline in listWaitDownLine + join order in listOrder on waitdownline.materielNo equals order.orderCode + select new BaseProductionOrderSplit + { + id = order.id, + lineCode = order.lineCode, + orderCode = order.orderCode + }).ToList(); + if (resultList?.Count > 0) + { + if (bianbie == 1) + { + string XianBie = resultList[0].lineCode; + char lastChar = XianBie[XianBie.Length - 1]; + var num = Char.GetNumericValue(lastChar).ToString(); + //string qx = num == "1" ? "2" : "1"; + return num; + } + else + { + var vin = resultList[0].orderCode; + return vin; + } + + } + else { return null; } + } + + /// + /// K18流转点去向控制(上件点损坏时不返回上件) + /// + /// 查找字段辨别 1为查找闸口是否维护损坏, 2 为损坏时查找K22人工设定走向 + /// 闸口名称 + /// + string GetFlag(int bianbie, string FlagName) + { + using var scope = _host.Services.CreateScope(); + using var dbContext = scope.ServiceProvider.GetRequiredService(); + var baseflag = dbContext.BaseAmima.Where(t => t.name == FlagName).ToList(); + + if (baseflag?.Count > 0) + { + if (bianbie == 1) + { + var flag = baseflag[0].password == "2" ? "2" : "1"; + return flag;//返回上件损坏闸口值 + } + else + { + var flag = baseflag[0].direction.ToString() == "1" ? "1" : "2"; + return flag;//返回上件损坏闸口值后维护K22去向 + } + } + return null; + } + } + catch (Exception ex) + { + LogManager.Info($"GetTargetTo 方法报错 >>> {ex.Message}"); + return null; + } + } + } +} diff --git a/src/Khd.Core.Wcs/Wcs/FourthFloorPoint.cs b/src/Khd.Core.Wcs/Wcs/FourthFloorPoint.cs new file mode 100644 index 0000000..c411f0f --- /dev/null +++ b/src/Khd.Core.Wcs/Wcs/FourthFloorPoint.cs @@ -0,0 +1,165 @@ +using Khd.Core.Domain.Models; +using Khd.Core.EntityFramework; +using Khd.Core.Library; +using Khd.Core.Library.Mapper; +using Khd.Core.Plc.S7; +using Khd.Core.Wcs.Global; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; +using Z.EntityFramework.Plus; + +namespace Khd.Core.Wcs.Wcs +{ + /// + /// 四楼接驳位 + /// + public class FourthFloorPoint + { + private readonly LoggerUtils _logger = new LoggerUtils(); + private readonly int Floor; + private readonly IHost _host; + private readonly BasePlcpoint LineRFID; + private readonly BasePlcpoint LineSignal; + public FourthFloorPoint(IHost host, int floor) + { + Floor = floor; + this._host = host; + this.LineRFID = StaticData.BasePlcpointList.First(t => t.plcpointNo == "RFID004"); + this.LineSignal = StaticData.BasePlcpointList.First(t => t.plcpointNo.Contains("linesignal04")); + } + + public void StartPoint() + { + Thread MonitorInLocatorPointThread = new Thread(MonitorInLocatorPoint); + MonitorInLocatorPointThread.IsBackground = true; + MonitorInLocatorPointThread.Name = "FourthFloorPoint"; + MonitorInLocatorPointThread.Start(); + Console.WriteLine($"{DateTime.Now}:四楼接驳位线程开始"); + } + + private void MonitorInLocatorPoint() + { + List ITypes = new List { 1, 3, 5, 7 }; + using var scope = _host.Services.CreateScope(); + using var dbContext = scope.ServiceProvider.GetRequiredService(); + while (true) + { + try + { + dbContext.ChangeTracker.Clear(); + //入库任务 + var rfid = StaticData.PlcDic[0].ReadRFID(LineRFID.plcpointAddress); + var isSignal = StaticData.PlcDic[0].Read(LineSignal.plcpointAddress); + if (rfid != null && isSignal != null) + { + if (Convert.ToInt32(isSignal) == 1)//托盘到位 + { + WcsTask? wcsTask = dbContext.WcsTask.Where(t => t.nextPointId == 4).FirstOrDefault(); + if (wcsTask != null) + { + if (wcsTask.taskStatus == 5)//提升机上来的 + { + //清除托盘信息 + MesBasePalletInfo? mesBasePalletInfo = dbContext.MesBasePalletInfo.FirstOrDefault(t => t.palletInfoCode == rfid); + if (mesBasePalletInfo != null) + { + MesBaseBarcodeInfo? mesBaseBarcodeInfo = dbContext.MesBaseBarcodeInfo.Where(t => t.palletInfoCode == rfid).FirstOrDefault(); + if (mesBaseBarcodeInfo != null) + { + mesBaseBarcodeInfo.palletInfoCode = null; + dbContext.Update(mesBaseBarcodeInfo); + } + mesBasePalletInfo.bindAmount = null; + mesBasePalletInfo.bindAmount = null; + mesBasePalletInfo.materialBarcode = null; + mesBasePalletInfo.materialCode = null; + mesBasePalletInfo.materialId = null; + mesBasePalletInfo.materialName = null; + mesBasePalletInfo.updateBy = "WCS"; + mesBasePalletInfo.updateTime = DateTime.Now; + dbContext.Update(mesBasePalletInfo); + dbContext.Remove(wcsTask); + dbContext.WcsTaskLog.Where(t => t.objid == wcsTask.objid).Update(t => new WcsTaskLog { taskStatus = 6 }); + dbContext.Remove(wcsTask); + dbContext.SaveChanges(); + } + } + } + else + { + bool hasTask = dbContext.WcsTask.Where(t => t.currPointId == 4 || (t.endPointId == 4 && t.taskStatus > 0)).Any(); + //如果有任务往当前楼层送,报警 + BaseEquip lineEquip = StaticData.BaseEquip.First(t => t.objid == 4); + BaseEquip nextEquip = StaticData.BaseEquip.First(t => t.objid == 6); + if (!hasTask) + { + MesBasePalletInfo? mesBasePalletInfo = dbContext.MesBasePalletInfo.Where(t => t.palletInfoCode == rfid).FirstOrDefault(); + if (mesBasePalletInfo != null) + { + var warehouseId = dbContext.WmsWarehouseMaterial.Where(t => t.storageType == "1" && t.storageId == mesBasePalletInfo.materialId).FirstOrDefault()?.warehouseId; + if (warehouseId != null) + { + var TargetFloor = dbContext.WmsBaseWarehouse.Where(t => t.warehouseId == warehouseId).FirstOrDefault(); + if (TargetFloor != null) + { + if (TargetFloor.warehouseFloor == Floor) + { + continue; + } + var dic = StaticData.BaseDictionary.Where(t => t.dicKey == "TaskType" && t.agvType == "I" && t.dicField == TargetFloor.warehouseInstockType).FirstOrDefault(); + if (dic != null) + { + var newTask = new WcsTask() + { + objid = StaticData.SnowId.NextId(), + serialNo = SystemData.GetSerialNo(dbContext), + taskType = Convert.ToInt32(dic.dicValue), + taskStatus = 0, + containerNo = rfid, + materialBarcode = mesBasePalletInfo.materialBarcode, + materialId = mesBasePalletInfo.materialId, + qty = Convert.ToInt32(mesBasePalletInfo.bindAmount), + currPointId = lineEquip.objid, + currPointNo = lineEquip.equipNo, + nextPointId = nextEquip.objid, + nextPointNo = nextEquip.equipNo, + endPointId = warehouseId, + fromFloorNo = 4, + floorNo = TargetFloor.warehouseFloor, + useFlag = 1, + createBy = "一楼接驳位", + createTime = DateTime.Now, + remark = "一楼创建入库任务" + }; + dbContext.Add(newTask); + WcsTaskLog wcsTaskLog = CoreMapper.Map(newTask); + dbContext.Add(wcsTaskLog); + dbContext.SaveChanges(); + } + } + } + } + } + } + } + } + } + catch (Exception ex) + { + if (ex is PlcException) + { + + } + else + { + _logger.Error(ex.Message + "\n" + ex.StackTrace); + } + } + finally + { + Thread.Sleep(1000); + } + } + } + } +} diff --git a/src/Khd.Core.Wcs/Wcs/OutWarePoint.cs b/src/Khd.Core.Wcs/Wcs/OutWarePoint.cs new file mode 100644 index 0000000..353019c --- /dev/null +++ b/src/Khd.Core.Wcs/Wcs/OutWarePoint.cs @@ -0,0 +1,253 @@ +using AngleSharp.Dom; +using Khd.Core.Domain.Dto.wcs; +using Khd.Core.Domain.Models; +using Khd.Core.EntityFramework; +using Khd.Core.Wcs.Global; +using Masuit.Tools.Logging; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; +using Microsoft.Extensions.Logging; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Khd.Core.Domain.Dto.webapi; + +using Khd.Core.Plc.S7; + +using Khd.Core.Wcs.Wcs; +using System.Data; +using Microsoft.EntityFrameworkCore; +using Z.EntityFramework.Plus; +using Masuit.Tools; +using Microsoft.IdentityModel.Tokens; + +namespace Khd.Core.Wcs.Wcs +{ + /// + /// 出库点线程 + /// + public class OutWarePoint + { + private readonly IHost _host; + private readonly Plc.S7.Plc _plc; + List ScanPoint { get; set; }//点位信息 + BaseSitenode? sitenode { get; set; }//站台信息 + + NodeSetting? NodeSettingCarNo { get; set; } + NodeSetting? NodeSettingCarState { get; set; } + NodeSetting? NodeSettingCarRun { get; set; } + NodeSetting? NodeSettingWcsState { get; set; } + NodeSetting? NodeSettingWcsSend { get; set; } + NodeSetting? NodeSettingWcsSendMaterial { get; set; } + NodeSetting? NodeSettingPLCSendSendMaterialstate { get; set; } + Thread FlowPointThread; + public OutWarePoint(IHost host, Plc.S7.Plc plc, string siteNo) + { + this._host = host; + this._plc = plc; + //this.ScanPoint = StaticData.NodeSettingList.Where(t => t.siteNo == siteNo).ToList();//加载当前站点所对应的点位 + this.sitenode = StaticData.SiteNodeList.FirstOrDefault(t => t.siteNo == siteNo);//获取当前站台信息 + this.NodeSettingCarNo = this.ScanPoint.FirstOrDefault(t => t.plcpointNo.Contains("carno")); + this.NodeSettingCarState = this.ScanPoint.FirstOrDefault(t => t.plcpointNo.Contains("carstate")); + this.NodeSettingCarRun = this.ScanPoint.FirstOrDefault(t => t.plcpointNo.Contains("carrun")); + this.NodeSettingWcsState = this.ScanPoint.FirstOrDefault(t => t.plcpointNo.Contains("plcsendK")); + this.NodeSettingWcsSend = this.ScanPoint.FirstOrDefault(t => t.plcpointNo.Contains("wcsend")); + this.NodeSettingWcsSendMaterial = this.ScanPoint.FirstOrDefault(t => t.plcpointNo.Contains("wcssendmessage")); + this.NodeSettingPLCSendSendMaterialstate = this.ScanPoint.FirstOrDefault(t => t.plcpointNo.Contains("plcsendmessage")); + try + { + //默认启动,清理plc的上位机写入点位值 + this._plc.Write(NodeSettingCarRun.plcpointAddress, MainCentralControl.QingKongDianWei); + this._plc.Write(NodeSettingWcsSend.plcpointAddress, MainCentralControl.QingKongDianWei); + this._plc.Write(NodeSettingWcsSendMaterial.plcpointAddress, MainCentralControl.QingKongDianWei); + } + catch (Exception ex) + { + Console.WriteLine("站点" + siteNo + " 初始化数据异常" + ex.Message); + LogManager.Error(ex); + } + } + /// + /// 启动上件扫描监听 + /// + public void StartPoint() + { + + FlowPointThread = new Thread(MonitorInLocatorPoint); + FlowPointThread.Start(); + } + public void MonitorInLocatorPoint() + { + while (true) + { + try + { + //通用逻辑下,根据上件记录表,可区分业务,入库,出库,回库 + //- 入库 - 根据小车任务表,可区分流入哪个站点 + //- 出库 - 根据小车任务表,可区分流入哪个站点 + //- 回库 - 根据小车任务表,可区分流入哪个站点 + //- 特殊逻辑:下一站点多个站点,按多条线缓存数优先进少的; + + var carno = this._plc.Read(NodeSettingCarNo.plcpointAddress); + var carstate = this._plc.Read(NodeSettingCarState.plcpointAddress); + var carrun = this._plc.Read(NodeSettingCarRun.plcpointAddress); + var wcsstate = this._plc.Read(NodeSettingWcsState.plcpointAddress); + var wcsend = this._plc.Read(NodeSettingWcsSend.plcpointAddress); + if (carno != null && carstate != null && carrun != null && wcsstate != null && wcsend != null) + { + //清除点位信息 + if (Convert.ToInt32(carno) == 0 && Convert.ToInt32(wcsend) == 1 && Convert.ToInt32(wcsstate) == 1) + { + this._plc.Write(NodeSettingCarRun.plcpointAddress, MainCentralControl.QingKongDianWei); //清空小车去向点位 + this._plc.Write(NodeSettingWcsSendMaterial.plcpointAddress, MainCentralControl.QingKongDianWei); //清空车身长度点位 + this._plc.Write(NodeSettingWcsSend.plcpointAddress, MainCentralControl.QingKongDianWei); //清空wcs处理完成点位 + } + //正常读到小车信息 + if (Convert.ToInt32(carno) > 0 && Convert.ToInt32(wcsend) == 0 && Convert.ToInt32(wcsstate) == 0 && Convert.ToInt32(carstate) == 1 && Convert.ToInt32(carrun) == 0) + { + var downLength = GetTargetTo(Convert.ToInt32(carno)); + if (string.IsNullOrWhiteSpace(downLength)) + { + //Console.WriteLine("OutWarePoint类 WriteMaterialMessage方法未确认返回值,查看报错日志!"); + Thread.Sleep(1000); + continue; + } + object ToInt16downLength = MainCentralControl.getValue("2", downLength); + this._plc.Write(this.NodeSettingCarRun.plcpointAddress, MainCentralControl.WcsMoRenQuXiang);//写入小车去向 + this._plc.Write(this.NodeSettingWcsSendMaterial.plcpointAddress, ToInt16downLength); //写入车身长度 + this._plc.Write(this.NodeSettingWcsSend.plcpointAddress, MainCentralControl.WcsChuLiWanCheng);//写入wcs处理完成 + string zfc = downLength == "2900" ? "空挂具" : "挂具"; + LogManager.Info($"当前时间{DateTime.Now} >>> {zfc}:{carno}经过下件站点:{this.sitenode.siteNo},WCS写入去向:1,写入车身长度:{ToInt16downLength};"); + } + } + } + catch (Exception ex) + { + LogManager.Error(ex); + } + finally + { + Thread.Sleep(2000); + } + } + } + + /// + /// 根据上件点,物料号,获取下一点位信息 + /// + /// 交互所属站点 + /// 到位挂具号码 + /// 是否是订单结束处理的判断传参 + /// + private string GetTargetTo(int carno) + { + try + { + using var scope = _host.Services.CreateScope(); + using var dbContext = scope.ServiceProvider.GetRequiredService(); + var basecarModel = dbContext.BaseCar.Where(t => t.carNo == carno).FirstOrDefault(); + var waitdownlineModel = dbContext.BaseWaitdownline.Where(t => t.carNo == carno).FirstOrDefault(); + if (waitdownlineModel == null && basecarModel != null) + { + //添加车辆在Waitdownline表中的缓存信息 + BaseWaitdownline waitdownModel = new() + { + id = Guid.NewGuid(), + carId = basecarModel.id, + carNo = basecarModel.carNo, + carName = basecarModel.carName, + downline = 2, + materielNo = "", + materielNum = 0, + isDelete = 0, + createTime = DateTime.Now, + createBy = "DownLine" + }; + dbContext.Add(waitdownModel); + dbContext.SaveChanges(); + return "2900";//调试无信息挂具写入数值 + } + else if (waitdownlineModel != null) + { + if (!string.IsNullOrWhiteSpace(waitdownlineModel.materielNo))//挂具绑定物料表中,物料不为空时 + { + //查找车型长度后返回写入Plc + string sqlQuery = @$" + SELECT + b1.material_no AS materialNo, + b1.k46up_length AS k46upLength, + b1.k48up_length AS k48upLength, + b1.down_length AS downLength, + b2.order_code AS definefield1, + b2.line_code AS definefield2, + b2.prod_code AS definefield3 + FROM + base_materialinfo b1 + JOIN base_production_order_split b2 + ON b2.prod_code LIKE CONCAT('%', b1.material_no, '%') + WHERE + b2.order_code = '{waitdownlineModel.materielNo}'"; + var QueryOrder = dbContext.ExecuteSqlQuery(sqlQuery).ToList(); + if (QueryOrder?.Count > 0 && !string.IsNullOrWhiteSpace(QueryOrder[0].downLength)) + { + RelieveCarAndMaterial(carno, waitdownlineModel.materielNo);//下件点下件解除挂具与物料信息绑定关系 + return QueryOrder[0].downLength; + } + } + else if (string.IsNullOrWhiteSpace(waitdownlineModel.materielNo))//挂具绑定物料表中,物料为空时 + { + return "2900";//与电气沟通是空时写入长度最小值 + } + } + //添加下线记录后修正任务和等待下线记录表 + void RelieveCarAndMaterial(int carno, string vin) + { + //挂具在下件点交互完成后记录下线数据 + var orderMessage = dbContext.BaseProductionOrderSplit.Where(t => t.orderCode == vin).ToList(); + if (orderMessage?.Count > 0 && waitdownlineModel != null) + { + string XianBie = orderMessage[0].lineCode; + char lastChar = XianBie[XianBie.Length - 1]; + var XianBieNum = Char.GetNumericValue(lastChar).ToString(); + BaseFollowmessage baseFollowmessage = new() + { + id = Guid.NewGuid().ToString(), + sid = orderMessage[0].id, + vinCode = orderMessage[0].orderCode, + upSite = waitdownlineModel.createBy, + downSite = XianBieNum == "1" ? "K02" : "K07", + carNo = carno, + materialName = orderMessage[0].prodDesc, + lineCode = orderMessage[0].lineCode, + lineName = orderMessage[0].lineCode == "一线" ? "一线" : "二线", + isover = 1, + est = orderMessage[0].est, + quantity = orderMessage[0].quantity, + actualquantity = 1, + productionSequence = orderMessage[0].productionSequence, + createBy = "OrderOverInsert", + createDate = DateTime.Now + }; + dbContext.Add(baseFollowmessage); + dbContext.SaveChanges(); + //解除base_waitdownline表中挂具与任务VIN码绑定关系,修改车辆线上状态为已下线 + dbContext.BaseWaitdownline.Where(t => t.id == waitdownlineModel.id).Update(a => new BaseWaitdownline() { materielNo = string.Empty, materielNum = 0, createTime = DateTime.Now, downline = 2, createBy = string.Empty, definefield1 = string.Empty}); + //修改base_production_order_split表订单为结束状态 + dbContext.BaseProductionOrderSplit.Where(t => t.id == orderMessage[0].id).Update(a => new BaseProductionOrderSplit() { isover = 1 }); + } + } + //LogManager.Info($"OutWarePoint类 WriteMaterialMessage方法未确认返回值,从底部返回NULL!"); + return ""; + } + catch (Exception ex) + { + //LogManager.Info($"错误日志输出 >>> OutWarePoint类 WriteMaterialMessage 方法报错 {ex}"); + LogManager.Error(ex); + return null; + } + + } + } +} diff --git a/src/Khd.Core.Wcs/Wcs/SecondFloor.cs b/src/Khd.Core.Wcs/Wcs/SecondFloor.cs new file mode 100644 index 0000000..015b44b --- /dev/null +++ b/src/Khd.Core.Wcs/Wcs/SecondFloor.cs @@ -0,0 +1,240 @@ +using Khd.Core.Domain.Dto.webapi; +using Khd.Core.Domain.Models; +using Khd.Core.EntityFramework; +using Khd.Core.Wcs.Global; +using Masuit.Tools.Logging; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; +using Newtonsoft.Json; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Khd.Core.Wcs.Wcs +{ + /// + /// 二楼调度 + /// + public class SecondFloor + { + List ScanPoint { get; set; }//点位信息 + private readonly IHost _host; + private readonly Plc.S7.Plc _plc; + BasePlcpoint? LineRFID { get; set; } + BasePlcpoint? LineWcsrun { get; set; } + BasePlcpoint? LineSignal { get; set; } + BasePlcpoint? LineIsPallet { get; set; } + BasePlcpoint? LineSerialNO { get; set; } + BasePlcpoint? LineFeedSeriaNo { get; set; } + Thread FlowPointThread; + int FloorNo { get; set; } + string EquipNo = ""; + public SecondFloor(IHost host, Plc.S7.Plc plc, int floor, string equipNo) + { + this._host = host; + this._plc = plc; + FloorNo = floor; + EquipNo = equipNo; + this.ScanPoint = StaticData.BasePlcpointList.Where(t => t.floorNo == floor).ToList();//加载当前站点所对应的点位 + this.LineRFID = this.ScanPoint.FirstOrDefault(t => t.plcpointNo.Contains("RFID")); + this.LineWcsrun = this.ScanPoint.FirstOrDefault(t => t.plcpointNo.Contains("wcsrun")); + this.LineSignal = this.ScanPoint.FirstOrDefault(t => t.plcpointNo.Contains("linesignal")); + this.LineIsPallet = this.ScanPoint.FirstOrDefault(t => t.plcpointNo.Contains("ispallet")); + this.LineSerialNO = this.ScanPoint.FirstOrDefault(t => t.plcpointNo.Contains("serialno")); + this.LineFeedSeriaNo = this.ScanPoint.FirstOrDefault(t => t.plcpointNo.Contains("feedserialno")); + + //var lineRFID = this._plc.Read(NodeSettingCarNo.plcpointAddress); + try + { + //默认启动,清理plc的上位机写入点位值 + this._plc.Write(LineRFID.plcpointAddress, MainCentralControl.QingKongDianWei); + } + catch (Exception ex) + { + Console.WriteLine("楼层" + floor + " 初始化数据异常" + ex.Message); + LogManager.Error(ex); + } + } + /// + /// 启动上件扫描监听 + /// + public void StartPoint() + { + + FlowPointThread = new Thread(MonitorInLocatorPoint); + FlowPointThread.Start(); + } + + public void MonitorInLocatorPoint() + { + using var scope = _host.Services.CreateScope(); + using var dbContext = scope.ServiceProvider.GetRequiredService(); + while (true) + { + try + { + //入库任务 + var rfid = this._plc.Read(LineRFID.plcpointAddress); + var isSignal = this._plc.Read(LineSignal.plcpointAddress); + var isPallet = this._plc.Read(LineIsPallet.plcpointAddress); + if (rfid != null && isSignal != null && isPallet != null) + { + //正常读到输送线信息 有到位信号,并且有托盘,获取条码信息 + if (Convert.ToInt32(isSignal) > 0 && Convert.ToInt32(isPallet) == 1) + { + //获取条码信息 + var palletNo = Convert.ToString(rfid); + //获取入库任务 + var wcsTask = GetTask(palletNo, FloorNo, EquipNo); + //判断是否为出库任务 + if (wcsTask.taskType == 2 || wcsTask.taskType == 3) + { + this._plc.Write(LineWcsrun.plcpointAddress, 1); + //更新任务下一点位为提升机 + wcsTask.nextPointId = 6; + wcsTask.nextPointNo = "T01"; + wcsTask.updateTime=DateTime.Now; + dbContext.Update(wcsTask); + dbContext.SaveChanges(); + } + else + { + //入库任务 + //下发agv任务 + SendTask(wcsTask); + } + } + } + + } + catch (Exception ex) + { + LogManager.Error(ex); + } + finally + { + Thread.Sleep(1000); + } + } + } + + //获取输送线上的任务 + public WcsTask GetTask(string containerNo, int floorNo, string equipNo) + { + using var scope = _host.Services.CreateScope(); + using var dbContext = scope.ServiceProvider.GetRequiredService(); + var wcsTask = new WcsTask(); + var wareHouseList = StaticData.WmsBaseWarehouse.ToList(); + try + { + //获取条码号,如果该条码任务存在就继续任务,如果条码不存在,创建入库任务并调度agv + var task = StaticData.WcsTask.Where(t => t.containerNo == containerNo).FirstOrDefault(); + if (task == null) + { + var palletInfo = StaticData.MesBasePalletInfo.Where(t => t.palletInfoCode == containerNo).FirstOrDefault(); + //查询该条码绑定的物料信息 + var material = StaticData.WmsWarehouseMaterial.Where(t => t.storageId == palletInfo.materialId).FirstOrDefault(); + var wareHouse = wareHouseList.Where(t => t.warehouseId == material.warehouseId).FirstOrDefault(); + var dic = StaticData.BaseDictionary.Where(t => t.dicKey == "TaskType" && t.ud1 == "I" && t.dicField == wareHouse.warehouseInstockType).FirstOrDefault(); + var equip = StaticData.BaseEquip.ToList(); + var startEquip = equip.Where(t => t.equipNo == equipNo).FirstOrDefault(); + var endPoint = wareHouseList.Where(t => t.warehouseFloor == floorNo).FirstOrDefault(); + //var currEquip= + if (palletInfo != null) + { + //自动获取id + Jc.SnowId.JcSnowId id = new Jc.SnowId.JcSnowId(1, 1); + var objid = id.NextId(); + WcsTask newTask = new() + { + objid = objid, + taskType = Convert.ToInt32(dic.dicValue), + containerNo = containerNo, + taskStatus = 0, + materialId = material.storageId, + qty = Convert.ToInt32(palletInfo.bindAmount), + startPointId = startEquip.objid, + startPointNo = equipNo, + currPointId = startEquip.objid, + currPointNo = equipNo, + endPointId = endPoint.warehouseId, + endPointNo = endPoint.warehouseCode, + }; + dbContext.Add(newTask); + dbContext.SaveChanges(); + wcsTask = newTask; + } + else + { + LogManager.Info(floorNo + "楼接驳位,托盘" + containerNo + "未绑定!"); + } + } + else + { + wcsTask = StaticData.WcsTask.Where(t => t.currPointNo == equipNo).FirstOrDefault(); + } + } + catch (Exception ex) + { + LogManager.Info(floorNo + "楼接驳位异常" + ex.Message); + throw; + } + return wcsTask; + } + /// + /// 下发任务 + /// + /// + public void SendTask(WcsTask task) + { + using var scope = _host.Services.CreateScope(); + using var dbContext = scope.ServiceProvider.GetRequiredService(); + //入库类型 + List taskInType = new List { 1, 3, 5, 7 }; + List taskOutType = new List { 2, 4, 6, 8 }; + try + { + //获取 + if (task == null) return; + if (taskInType.Contains(task.taskType.GetValueOrDefault())) + { + //首先判断是否已下发指令 + var cmd = StaticData.WcsCmd.Where(t => t.taskId == task.objid).FirstOrDefault(); + //指令表存在说明已下发 + if (cmd != null) return; + //获取下发agv指令 + string ip = ""; int port = 0; string url = ""; + RequestAGVTaskDto agvtask = new RequestAGVTaskDto(); + agvtask.reqCode = task.serialNo.ToString(); + var json = JsonConvert.SerializeObject(agvtask); + HttpHelper.SendPostMessage(ip, port, url, json); + //未下发给agv下发指令 + WcsCmd taskCmd = new WcsCmd() + { + taskId = task.objid, + cmdType = task.taskType, + serialNo = task.serialNo, + equipmentNo = task.equipmentNo, + cmdStatus = 1, + createBy = "", + createTime = DateTime.Now, + }; + dbContext.Add(taskCmd); + dbContext.SaveChanges(); + } + else + { + + } + + } + catch (Exception) + { + + throw; + } + } + } +} diff --git a/src/Khd.Core.Wcs/Wcs/SecondFloorAGV.cs b/src/Khd.Core.Wcs/Wcs/SecondFloorAGV.cs new file mode 100644 index 0000000..2c7ad4c --- /dev/null +++ b/src/Khd.Core.Wcs/Wcs/SecondFloorAGV.cs @@ -0,0 +1,1104 @@ +using Khd.Core.Domain.Dto.TaskType; +using Khd.Core.Domain.Dto.webapi; +using Khd.Core.Domain.Models; +using Khd.Core.EntityFramework; +using Khd.Core.Library; +using Khd.Core.Plc.S7; +using Khd.Core.Wcs.Global; +using Masuit.Tools; +using Microsoft.EntityFrameworkCore; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; +using Newtonsoft.Json; +using Z.EntityFramework.Plus; + +namespace Khd.Core.Wcs.Wcs +{ + /// + /// 二楼AGV调度 + /// + public class SecondFloorAGV + { + private readonly IHost _host; + private readonly LoggerUtils _logger = new LoggerUtils(); + private int FloorNo { get; set; } + private int EquipID = 8; //2楼AGV + + public SecondFloorAGV(IHost host, int floor) + { + this._host = host; + FloorNo = floor; + } + + /// + /// 启动上件扫描监听 + /// + public void StartPoint() + { + Thread FlowPointThread = new Thread(MonitorInLocatorPoint); + FlowPointThread.IsBackground = true; + FlowPointThread.Name = "SecondFloorAGV"; + FlowPointThread.Start(); + Console.WriteLine(DateTime.Now + ":二楼AGV上件扫描监听启动成功"); + _logger.Info("二楼AGV上件扫描监听启动成功"); + } + + /// + /// 开启线程监听2分钟小包出口光电信号,如果小包出口到位信号消失,即取托盘完成,发送信号通知线体 + /// + /// + public static void ListenForSignal(int timeoutMinutes = 2) + { + // 创建一个 CancellationTokenSource 来控制超时 + var cts = new CancellationTokenSource(TimeSpan.FromMinutes(timeoutMinutes)); + + Task.Run(async () => + { + var agvGetPoint = StaticData.BasePlcpointList.First(t => t.id == 53); + var agvGetValue = StaticData.PlcDic[2].Read(agvGetPoint.plcpointAddress); + + while (!cts.Token.IsCancellationRequested) + { + // 每隔 1 秒检查一次小包出口光电信号 + await Task.Delay(1000, cts.Token); + + agvGetValue = StaticData.PlcDic[2].Read(agvGetPoint.plcpointAddress); + + if (agvGetValue != null && Convert.ToInt32(agvGetValue) == 0) + { + // 信号消失,20s后执行相关操作 + Thread.Sleep(1000 * 20); + + // 取托盘确认信号DB4.DBX310.1写true + BasePlcpoint secondOutGetOverPoint = StaticData.BasePlcpointList.First(t => t.id == 71); + StaticData.PlcDic[2].WriteToPoint(secondOutGetOverPoint.plcpointAddress, true, secondOutGetOverPoint.plcpointLength.ToString()); + + // 清空小包出口RFID + BasePlcpoint rfid2001Point = StaticData.BasePlcpointList.First(t => t.id == 52); + StaticData.PlcDic[2].WriteRFID(rfid2001Point.plcpointAddress, "", 12); + + // 满足条件后退出循环 + break; + } + } + + // 任务被取消或者超时 + if (cts.Token.IsCancellationRequested) + { + Console.WriteLine("任务超时或被取消"); + } + }).Wait(); + } + + public void MonitorInLocatorPoint() + { + using var scope = _host.Services.CreateScope(); + using var dbContext = scope.ServiceProvider.GetRequiredService(); + BaseEquip inEquip = StaticData.BaseEquip.First(t => t.objid == 36); + BaseEquip outEquip = StaticData.BaseEquip.First(t => t.objid == 37); + BaseEquip lineEquip = StaticData.BaseEquip.First(t => t.objid == 2); + BaseEquip baseEquip = StaticData.BaseEquip.First(t => t.objid == EquipID); + BaseEquip wasteEquip = StaticData.BaseEquip.First(t => t.objid == 38); + while (true) + { + try + { + dbContext.ChangeTracker.Clear(); + //获取条码号,如果该条码任务存在就继续任务,如果条码不存在,创建入库任务并调度agv + var taskList = dbContext.WcsTask + .Where(t => t.useFlag == 1) + .Where(t => t.IsDelete == 0 || t.IsDelete == null) + .Where(t => t.nextPointId == EquipID).OrderBy(t => t.createTime).ToList(); + foreach (var item in taskList) + { + item.updateTime = DateTime.Now; + if (taskList.Where(t => t.objid != item.objid && t.taskStatus > 0).Any()) + { + continue; + } + if (item.taskStatus == 0)//下发任务 + { + BaseDictionary baseDictionary = StaticData.BaseDictionary.First(t => t.objid == item.taskType); + if (item.taskType == StaticTaskType.SecondLineToSmallPackage)//输送线-小包入口 + { + var agvTask = new RequestAGVTaskDto + { + reqCode = StaticData.SnowId.NextId().ToString(), + positionCodePath = new List + { + new () + { + positionCode= lineEquip.agvPositionCode, + type="00" + }, + new () + { + positionCode=inEquip.agvPositionCode, + type="00" + } + }, + taskTyp = baseDictionary.dicValue, + ctnrTyp = "2", + }; + string message = JsonConvert.SerializeObject(agvTask); + string result = HttpHelper.SendPostMessage(baseEquip.serverIp, baseEquip.serverPort.Value, "rcms/services/rest/hikRpcService/genAgvSchedulingTask", message); + var reponseMessage = JsonConvert.DeserializeObject(result); + if (reponseMessage != null && reponseMessage.message == "成功") + { + _logger.Info("二楼AGV线程下发任务" + agvTask.ToJsonString() + "\n" + message); + Console.WriteLine(DateTime.Now + ":二楼AGV线程下发任务" + item.currPointNo + "," + item.endPointNo); + item.taskCode = reponseMessage.data; + item.taskStatus = 1; + dbContext.Update(item); + dbContext.WcsTaskLog.Where(t => t.objid == item.objid).Update(t => new WcsTaskLog() { taskStatus = 1 }); + dbContext.SaveChanges(); + } + else + { + _logger.Info("五楼Agv下发任务失败" + item.taskType + result); + } + } + else if (item.taskType == StaticTaskType.SecondWasteToTransit)//废料工位-库位 + { + var endEquip = StaticData.BaseEquip.First(t => t.objid == item.endPointId); + var agvTask = new RequestAGVTaskDto + { + reqCode = StaticData.SnowId.NextId().ToString(), + positionCodePath = new List + { + new () + { + positionCode=wasteEquip.agvPositionCode, + type="00" + }, + new () + { + positionCode= endEquip.agvPositionCode, + type="00" + } + }, + taskTyp = baseDictionary.dicValue, + ctnrTyp = "2", + }; + string message = JsonConvert.SerializeObject(agvTask); + string result = HttpHelper.SendPostMessage(baseEquip.serverIp, baseEquip.serverPort.Value, "rcms/services/rest/hikRpcService/genAgvSchedulingTask", message); + + var reponseMessage = JsonConvert.DeserializeObject(result); + if (reponseMessage != null && reponseMessage.message == "成功") + { + _logger.Info("二楼AGV线程下发任务" + agvTask.ToJsonString() + "\n" + message); + Console.WriteLine(DateTime.Now + ":二楼AGV线程下发任务" + item.currPointNo + "," + item.endPointNo); + item.taskCode = reponseMessage.data; + item.taskStatus = 1; + dbContext.Update(item); + dbContext.WcsTaskLog.Where(t => t.objid == item.objid).Update(t => new WcsTaskLog() { taskStatus = 1 }); + dbContext.SaveChanges(); + } + else + { + _logger.Info("五楼Agv下发任务失败" + item.taskType + result); + } + } + else if (item.taskType == StaticTaskType.SecondSmallPackageToStorage)//小包出口-库位 + { + BaseEquip startEquip = dbContext.BaseEquip.First(t => t.objid == item.currPointId); + var agvTask = new RequestAGVTaskDto + { + reqCode = StaticData.SnowId.NextId().ToString(), + positionCodePath = new List + { + new () + { + positionCode=startEquip.agvPositionCode, + type="00" + }, + new () + { + positionCode=item.endPointNo, + type="00" + } + }, + taskTyp = baseDictionary.dicValue, + ctnrTyp = "2", + }; + string message = JsonConvert.SerializeObject(agvTask); + string result = HttpHelper.SendPostMessage(baseEquip.serverIp, baseEquip.serverPort.Value, "rcms/services/rest/hikRpcService/genAgvSchedulingTask", message); + var reponseMessage = JsonConvert.DeserializeObject(result); + if (reponseMessage != null && reponseMessage.message == "成功") + { + _logger.Info("二楼AGV线程下发任务" + agvTask.ToJsonString() + "\n" + message); + Console.WriteLine(DateTime.Now + ":二楼AGV线程下发任务" + item.currPointNo + "," + item.endPointNo); + item.taskCode = reponseMessage.data; + item.taskStatus = 1; + dbContext.Update(item); + dbContext.WcsTaskLog.Where(t => t.objid == item.objid).Update(t => new WcsTaskLog() { taskStatus = 1 }); + dbContext.SaveChanges(); + } + else + { + _logger.Info("二楼Agv下发任务失败" + item.taskType + result); + } + } + else if (item.taskType == StaticTaskType.SecondTransitToLift)//周转位-提升机 + { + var startPoint = StaticData.BaseEquip.First(t => t.objid == item.currPointId); + if (lineEquip.equipStatus == 0) + { + var agvTask = new RequestAGVTaskDto + { + reqCode = StaticData.SnowId.NextId().ToString(), + positionCodePath = new List + { + new () + { + positionCode=startPoint.agvPositionCode, + type="00" + }, + new () + { + positionCode=lineEquip.agvPositionCode, + type="00" + } + }, + taskTyp = baseDictionary.dicValue, + ctnrTyp = "2", + }; + string message = JsonConvert.SerializeObject(agvTask); + string result = HttpHelper.SendPostMessage(baseEquip.serverIp, baseEquip.serverPort.Value, "rcms/services/rest/hikRpcService/genAgvSchedulingTask", message); + var reponseMessage = JsonConvert.DeserializeObject(result); + if (reponseMessage != null && reponseMessage.message == "成功") + { + _logger.Info("二楼AGV线程下发任务" + agvTask.ToJsonString() + "\n" + message); + Console.WriteLine(DateTime.Now + ":二楼AGV线程下发任务" + item.currPointNo + "," + item.endPointNo); + item.taskCode = reponseMessage.data; + item.taskStatus = 1; + dbContext.Update(item); + dbContext.WcsTaskLog.Where(t => t.objid == item.objid).Update(t => new WcsTaskLog() { taskStatus = 1 }); + dbContext.SaveChanges(); + } + else + { + _logger.Info("2楼Agv下发任务失败" + item.taskType + result); + } + } + else + { + continue; + } + } + else if (item.taskType == StaticTaskType.SecondStorageToLift)//库位-提升机 + { + var startPoint = dbContext.WmsBaseLocation.First(t => t.locationId == item.currPointId); + lineEquip = dbContext.BaseEquip.First(t => t.objid == 2); + if (lineEquip.equipStatus == 0) + { + var agvTask = new RequestAGVTaskDto + { + reqCode = StaticData.SnowId.NextId().ToString(), + positionCodePath = new List + { + new () + { + positionCode=startPoint.agvPositionCode, + type="00" + }, + new () + { + positionCode= lineEquip.agvPositionCode, + type="00" + } + }, + taskTyp = baseDictionary.dicValue, + ctnrTyp = "2", + }; + string message = JsonConvert.SerializeObject(agvTask); + string result = HttpHelper.SendPostMessage(baseEquip.serverIp, baseEquip.serverPort.Value, "rcms/services/rest/hikRpcService/genAgvSchedulingTask", message); + var reponseMessage = JsonConvert.DeserializeObject(result); + if (reponseMessage != null && reponseMessage.message == "成功") + { + _logger.Info("二楼AGV线程下发任务" + agvTask.ToJsonString() + "\n" + message); + Console.WriteLine(DateTime.Now + ":二楼AGV线程下发任务" + item.currPointNo + "," + item.endPointNo); + item.taskCode = reponseMessage.data; + item.taskStatus = 1; + lineEquip.equipStatus = 1; + dbContext.Update(lineEquip); + dbContext.Update(item); + dbContext.WcsTaskLog.Where(t => t.objid == item.objid).Update(t => new WcsTaskLog() { taskStatus = 1 }); + dbContext.SaveChanges(); + } + else + { + _logger.Info("五楼Agv下发任务失败" + item.taskType + result); + } + } + else + { + continue; + } + } + else if (item.taskType == StaticTaskType.SecondRemove)//2F移库 + { + var agvTask = new RequestAGVTaskDto + { + reqCode = StaticData.SnowId.NextId().ToString(), + positionCodePath = new List + { + new() + { + positionCode = item.currPointNo, + type = "00" + }, + new() + { + positionCode = item.endPointNo, + type = "00" + } + }, + taskTyp = baseDictionary.dicValue, + ctnrTyp = "2", + }; + string message = JsonConvert.SerializeObject(agvTask); + string result = HttpHelper.SendPostMessage(baseEquip.serverIp, baseEquip.serverPort.Value, "rcms/services/rest/hikRpcService/genAgvSchedulingTask", message); + var reponseMessage = JsonConvert.DeserializeObject(result); + if (reponseMessage != null && reponseMessage.message == "成功") + { + _logger.Info("二楼AGV线程下发任务" + agvTask.ToJsonString() + "\n" + message); + Console.WriteLine(DateTime.Now + ":二楼AGV线程下发任务" + item.currPointNo + "," + item.endPointNo); + item.taskCode = reponseMessage.data; + item.taskStatus = 1; + dbContext.Update(item); + dbContext.WcsTaskLog.Where(t => t.objid == item.objid).Update(t => new WcsTaskLog() { taskStatus = 1 }); + dbContext.SaveChanges(); + } + else + { + _logger.Info("五楼Agv下发任务失败" + item.taskType + result); + } + } + else if (item.taskType == StaticTaskType.SecondLiftToWaste)//提升机-废料工位 + { + var agvTask = new RequestAGVTaskDto + { + reqCode = StaticData.SnowId.NextId().ToString(), + positionCodePath = new List + { + new () + { + positionCode=lineEquip.agvPositionCode, + type="00" + }, + new () + { + positionCode=wasteEquip.agvPositionCode, + type="00" + } + }, + taskTyp = baseDictionary.dicValue, + ctnrTyp = "2", + }; + string message = JsonConvert.SerializeObject(agvTask); + string result = HttpHelper.SendPostMessage(baseEquip.serverIp, baseEquip.serverPort.Value, "rcms/services/rest/hikRpcService/genAgvSchedulingTask", message); + var reponseMessage = JsonConvert.DeserializeObject(result); + if (reponseMessage != null && reponseMessage.message == "成功") + { + _logger.Info("二楼AGV线程下发任务" + agvTask.ToJsonString() + "\n" + message); + Console.WriteLine(DateTime.Now + ":二楼AGV线程下发任务" + item.currPointNo + "," + item.endPointNo); + item.taskCode = reponseMessage.data; + item.taskStatus = 1; + dbContext.Update(item); + dbContext.WcsTaskLog.Where(t => t.objid == item.objid).Update(t => new WcsTaskLog() { taskStatus = 1 }); + dbContext.SaveChanges(); + } + else + { + _logger.Info("五楼Agv下发任务失败" + item.taskType + result); + } + } + else if (item.taskType == StaticTaskType.SecondTransitToWaste)//周转位-废料工位 + { + var wasteEquipLocation = StaticData.BaseEquip.FirstOrDefault(t => t.objid == item.currPointId); + if (wasteEquipLocation != null) + { + var agvTask = new RequestAGVTaskDto + { + reqCode = StaticData.SnowId.NextId().ToString(), + positionCodePath = new List + { + new () + { + positionCode=wasteEquipLocation.agvPositionCode, + type="00" + }, + new () + { + positionCode=wasteEquip.agvPositionCode, + type="00" + } + }, + taskTyp = baseDictionary.dicValue, + ctnrTyp = "2", + }; + string message = JsonConvert.SerializeObject(agvTask); + string result = HttpHelper.SendPostMessage(baseEquip.serverIp, baseEquip.serverPort.Value, "rcms/services/rest/hikRpcService/genAgvSchedulingTask", message); + var reponseMessage = JsonConvert.DeserializeObject(result); + if (reponseMessage != null && reponseMessage.message == "成功") + { + _logger.Info("二楼AGV线程下发任务" + agvTask.ToJsonString() + "\n" + message); + Console.WriteLine(DateTime.Now + ":二楼AGV线程下发任务" + item.currPointNo + "," + item.endPointNo); + item.taskCode = reponseMessage.data; + item.taskStatus = 1; + dbContext.Update(item); + dbContext.WcsTaskLog.Where(t => t.objid == item.objid).Update(t => new WcsTaskLog() { taskStatus = 1 }); + dbContext.SaveChanges(); + } + else + { + _logger.Info("五楼Agv下发任务失败" + item.taskType + result); + } + } + } + else if (item.taskType == StaticTaskType.SecondLiftToTransit)//提升机到周转位 + { + var endEquip = StaticData.BaseEquip.First(t => t.objid == item.endPointId); + var agvTask = new RequestAGVTaskDto + { + reqCode = StaticData.SnowId.NextId().ToString(), + positionCodePath = new List + { + new () + { + positionCode=lineEquip.agvPositionCode, + type="00" + }, + new () + { + positionCode=endEquip.agvPositionCode, + type="00" + } + }, + taskTyp = baseDictionary.dicValue, + ctnrTyp = "2", + }; + string message = JsonConvert.SerializeObject(agvTask); + string result = HttpHelper.SendPostMessage(baseEquip.serverIp, baseEquip.serverPort.Value, "rcms/services/rest/hikRpcService/genAgvSchedulingTask", message); + var reponseMessage = JsonConvert.DeserializeObject(result); + if (reponseMessage != null && reponseMessage.message == "成功") + { + _logger.Info("二楼AGV线程下发任务" + agvTask.ToJsonString() + "\n" + message); + Console.WriteLine(DateTime.Now + ":二楼AGV线程下发任务" + item.currPointNo + "," + item.endPointNo); + item.taskCode = reponseMessage.data; + item.taskStatus = 1; + dbContext.Update(item); + dbContext.WcsTaskLog.Where(t => t.objid == item.objid).Update(t => new WcsTaskLog() { taskStatus = 1 }); + dbContext.SaveChanges(); + } + else + { + _logger.Info("五楼Agv下发任务失败" + item.taskType + result); + } + } + else if (item.taskType == StaticTaskType.SecondTransitToSmallPackage)//周转位-小包入口 + { + BaseEquip startEquip = StaticData.BaseEquip.First(t => t.objid == item.currPointId); + + var agvTask = new RequestAGVTaskDto + { + reqCode = StaticData.SnowId.NextId().ToString(), + positionCodePath = new List + { + new () + { + positionCode=startEquip.agvPositionCode, + type="00" + }, + new () + { + positionCode=inEquip.agvPositionCode, + type="00" + } + }, + taskTyp = baseDictionary.dicValue, + ctnrTyp = "2", + }; + string message = JsonConvert.SerializeObject(agvTask); + string result = HttpHelper.SendPostMessage(baseEquip.serverIp, baseEquip.serverPort.Value, "rcms/services/rest/hikRpcService/genAgvSchedulingTask", message); + var reponseMessage = JsonConvert.DeserializeObject(result); + if (reponseMessage != null && reponseMessage.message == "成功") + { + _logger.Info("二楼AGV线程下发任务" + agvTask.ToJsonString() + "\n" + message); + Console.WriteLine(DateTime.Now + ":二楼AGV线程下发任务" + item.currPointNo + "," + item.endPointNo); + item.taskCode = reponseMessage.data; + item.taskStatus = 1; + dbContext.Update(item); + dbContext.WcsTaskLog.Where(t => t.objid == item.objid).Update(t => new WcsTaskLog() { taskStatus = 1 }); + dbContext.SaveChanges(); + } + else + { + _logger.Info("五楼Agv下发任务失败" + item.taskType + result); + } + } + } + else + { + if (item.taskStatus == 3) + { + _logger.Info("二楼AGV线程继续任务" + item.objid); + if (item.taskType == StaticTaskType.SecondStorageToLift || item.taskType == StaticTaskType.SecondTransitToLift) + { + var lineSignal02 = StaticData.PlcDic[0].Read(StaticData.BasePlcpointList.First(t => t.plcpointNo == "linesignal02").plcpointAddress); + var wcsrun = StaticData.PlcDic[0].Read(StaticData.BasePlcpointList.First(t => t.plcpointNo == "wcsrun02").plcpointAddress); + if (lineSignal02 != null && lineSignal02.ToString() == "0" && wcsrun != null && wcsrun.ToString() == "0") + { + var agvTask = new RequestAGVTaskDto + { + reqCode = StaticData.SnowId.NextId().ToString(), + taskCode = item.taskCode + }; + string message = JsonConvert.SerializeObject(agvTask); + string result = HttpHelper.SendPostMessage(baseEquip.serverIp, baseEquip.serverPort.Value, "rcms/services/rest/hikRpcService/continueTask", message); + ReponseMessage? reponseMessage = JsonConvert.DeserializeObject(result); + if (reponseMessage != null && reponseMessage.message == "成功") + { + dbContext.WcsTask.Where(t => t.objid == item.objid).Update(t => new WcsTask() { taskStatus = 4 }); + dbContext.WcsTaskLog.Where(t => t.objid == item.objid).Update(t => new WcsTaskLog() { taskStatus = 4 }); + } + } + } + else if (item.currPointId == lineEquip.objid) + { + var lineSignal02 = StaticData.PlcDic[0].Read(StaticData.BasePlcpointList.First(t => t.plcpointNo == "linesignal02").plcpointAddress); + if (lineSignal02 != null && lineSignal02.ToString() == "1") + { + var agvTask = new RequestAGVTaskDto + { + reqCode = StaticData.SnowId.NextId().ToString(), + taskCode = item.taskCode + }; + string message = JsonConvert.SerializeObject(agvTask); + string result = HttpHelper.SendPostMessage(baseEquip.serverIp, baseEquip.serverPort.Value, "rcms/services/rest/hikRpcService/continueTask", message); + ReponseMessage? reponseMessage = JsonConvert.DeserializeObject(result); + if (reponseMessage != null && reponseMessage.message == "成功") + { + dbContext.WcsTask.Where(t => t.objid == item.objid).Update(t => new WcsTask() { taskStatus = 4 }); + dbContext.WcsTaskLog.Where(t => t.objid == item.objid).Update(t => new WcsTaskLog() { taskStatus = 4 }); + } + } + } + else if (item.currPointId == wasteEquip.objid) + { + if (true) + { + var agvTask = new RequestAGVTaskDto + { + reqCode = StaticData.SnowId.NextId().ToString(), + taskCode = item.taskCode + }; + string message = JsonConvert.SerializeObject(agvTask); + string result = HttpHelper.SendPostMessage(baseEquip.serverIp, baseEquip.serverPort.Value, "rcms/services/rest/hikRpcService/continueTask", message); + ReponseMessage? reponseMessage = JsonConvert.DeserializeObject(result); + if (reponseMessage != null && reponseMessage.message == "成功") + { + dbContext.WcsTask.Where(t => t.objid == item.objid).Update(t => new WcsTask() { taskStatus = 4 }); + dbContext.WcsTaskLog.Where(t => t.objid == item.objid).Update(t => new WcsTaskLog() { taskStatus = 4 }); + } + } + } + else if (item.taskType == StaticTaskType.SecondLineToSmallPackage) + { + // 托盘库叫料信号 + var agvPutPoint = StaticData.BasePlcpointList.First(t => t.id == 54); + //2F托盘库产线数据通讯情况 + var ConnectStatus2FPoint = StaticData.BasePlcpointList.First(t => t.id == 73); + //2F托盘库入口上料光电 + var PalletInIsHas2FPoint = StaticData.BasePlcpointList.First(t => t.id == 74); + + var agvPutValue = StaticData.PlcDic[2].Read(agvPutPoint.plcpointAddress);//托盘库叫料信号 + var ConnectStatus2F = StaticData.PlcDic[2].Read(ConnectStatus2FPoint.plcpointAddress);//2F托盘库产线数据通讯情况 + var PalletInIsHas2F = StaticData.PlcDic[2].Read(PalletInIsHas2FPoint.plcpointAddress);//2F托盘库入口上料光电 + + if (agvPutValue != null && ConnectStatus2F != null && PalletInIsHas2F != null && Convert.ToInt32(agvPutValue) == 1 && Convert.ToInt32(ConnectStatus2F) == 1 && Convert.ToInt32(PalletInIsHas2F) == 0) + { + // 托盘库叫料信号,并且通讯正常,并且小包入口无料 ,才可放托盘 + var agvTask = new RequestAGVTaskDto + { + reqCode = StaticData.SnowId.NextId().ToString(), + taskCode = item.taskCode + }; + string message = JsonConvert.SerializeObject(agvTask); + string result = HttpHelper.SendPostMessage(baseEquip.serverIp, baseEquip.serverPort.Value, "rcms/services/rest/hikRpcService/continueTask", message); + ReponseMessage? reponseMessage = JsonConvert.DeserializeObject(result); + if (reponseMessage != null && reponseMessage.message == "成功") + { + dbContext.WcsTask.Where(t => t.objid == item.objid).Update(t => new WcsTask() { taskStatus = 6 }); + dbContext.WcsTaskLog.Where(t => t.objid == item.objid).Update(t => new WcsTaskLog() { taskStatus = 6 }); + } + } + } + else if (item.currPointId == outEquip.objid) + { + var agvGetPoint = StaticData.BasePlcpointList.First(t => t.id == 53); + var agvGetValue = StaticData.PlcDic[2].Read(agvGetPoint.plcpointAddress);//小包出口的到位 + if (agvGetValue != null && (bool)agvGetValue == true) + { + var agvTask = new RequestAGVTaskDto + { + reqCode = StaticData.SnowId.NextId().ToString(), + taskCode = item.taskCode + }; + string message = JsonConvert.SerializeObject(agvTask); + string result = HttpHelper.SendPostMessage(baseEquip.serverIp, baseEquip.serverPort.Value, "rcms/services/rest/hikRpcService/continueTask", message); + ReponseMessage? reponseMessage = JsonConvert.DeserializeObject(result); + if (reponseMessage != null && reponseMessage.message == "成功") + { + dbContext.WcsTask.Where(t => t.objid == item.objid).Update(t => new WcsTask() { taskStatus = 4 }); + dbContext.WcsTaskLog.Where(t => t.objid == item.objid).Update(t => new WcsTaskLog() { taskStatus = 4 }); + + // 开启线程监听2分钟小包出口光电信号,如果小包出口到位信号消失,即取托盘完成,发送信号通知线体 + ListenForSignal(2); + } + } + } + else + { + var agvTask = new RequestAGVTaskDto + { + reqCode = StaticData.SnowId.NextId().ToString(), + taskCode = item.taskCode + }; + string message = JsonConvert.SerializeObject(agvTask); + string result = HttpHelper.SendPostMessage(baseEquip.serverIp, baseEquip.serverPort.Value, "rcms/services/rest/hikRpcService/continueTask", message); + ReponseMessage? reponseMessage = JsonConvert.DeserializeObject(result); + if (reponseMessage != null && reponseMessage.message == "成功") + { + dbContext.WcsTask.Where(t => t.objid == item.objid).Update(t => new WcsTask() { taskStatus = 4 }); + dbContext.WcsTaskLog.Where(t => t.objid == item.objid).Update(t => new WcsTaskLog() { taskStatus = 4 }); + } + } + } + else if (item.taskStatus == 5) + { + if (item.taskType == StaticTaskType.SecondStorageToLift || item.taskType == StaticTaskType.SecondTransitToLift) + { + var lineSignal02 = StaticData.PlcDic[0].Read(StaticData.BasePlcpointList.First(t => t.plcpointNo == "linesignal02").plcpointAddress); + var wcsrun = StaticData.PlcDic[0].Read(StaticData.BasePlcpointList.First(t => t.plcpointNo == "wcsrun02").plcpointAddress); + if (lineSignal02 != null && lineSignal02.ToString() == "0" && wcsrun != null && wcsrun.ToString() == "0") + { + var agvTask = new RequestAGVTaskDto + { + reqCode = StaticData.SnowId.NextId().ToString(), + taskCode = item.taskCode + }; + string message = JsonConvert.SerializeObject(agvTask); + string result = HttpHelper.SendPostMessage(baseEquip.serverIp, baseEquip.serverPort.Value, "rcms/services/rest/hikRpcService/continueTask", message); + ReponseMessage? reponseMessage = JsonConvert.DeserializeObject(result); + if (reponseMessage != null && reponseMessage.message == "成功") + { + dbContext.WcsTask.Where(t => t.objid == item.objid).Update(t => new WcsTask() { taskStatus = 4 }); + dbContext.WcsTaskLog.Where(t => t.objid == item.objid).Update(t => new WcsTaskLog() { taskStatus = 4 }); + } + } + } + else if (item.taskType == StaticTaskType.SecondLineToSmallPackage) + { + // 托盘库叫料信号 + var agvPutPoint = StaticData.BasePlcpointList.First(t => t.id == 54); + //2F托盘库产线数据通讯情况 + var ConnectStatus2FPoint = StaticData.BasePlcpointList.First(t => t.id == 73); + //2F托盘库入口上料光电 + var PalletInIsHas2FPoint = StaticData.BasePlcpointList.First(t => t.id == 74); + + var agvPutValue = StaticData.PlcDic[2].Read(agvPutPoint.plcpointAddress);//托盘库叫料信号 + var ConnectStatus2F = StaticData.PlcDic[2].Read(ConnectStatus2FPoint.plcpointAddress);//2F托盘库产线数据通讯情况 + var PalletInIsHas2F = StaticData.PlcDic[2].Read(PalletInIsHas2FPoint.plcpointAddress);//2F托盘库入口上料光电 + + if (agvPutValue != null && ConnectStatus2F != null && PalletInIsHas2F != null && Convert.ToInt32(agvPutValue) == 1 && Convert.ToInt32(ConnectStatus2F) == 1 && Convert.ToInt32(PalletInIsHas2F) == 0) + { + // 托盘库叫料信号,并且通讯正常,并且小包入口无料 ,才可放托盘 + var agvTask = new RequestAGVTaskDto + { + reqCode = StaticData.SnowId.NextId().ToString(), + taskCode = item.taskCode + }; + string message = JsonConvert.SerializeObject(agvTask); + string result = HttpHelper.SendPostMessage(baseEquip.serverIp, baseEquip.serverPort.Value, "rcms/services/rest/hikRpcService/continueTask", message); + ReponseMessage? reponseMessage = JsonConvert.DeserializeObject(result); + if (reponseMessage != null && reponseMessage.message == "成功") + { + dbContext.WcsTask.Where(t => t.objid == item.objid).Update(t => new WcsTask() { taskStatus = 6 }); + dbContext.WcsTaskLog.Where(t => t.objid == item.objid).Update(t => new WcsTaskLog() { taskStatus = 6 }); + } + } + } + } + else if (item.taskStatus == 7) + { + if (item.currPointId == 2) + { + lineEquip = dbContext.BaseEquip.First(t => t.objid == 2); + lineEquip.equipStatus = 0; + dbContext.Update(lineEquip); + } + if (item.taskType == StaticTaskType.SecondSmallPackageToStorage) //小包出口到库位 + { + //WmsProductInstock? wmsProductInstock = dbContext.WmsProductInstock.FirstOrDefault(t => t.productInstockId == item.orderId); + //if (wmsProductInstock != null) + //{ + // WmsProductInstockDetail? wmsProductInstockDetail = dbContext.WmsProductInstockDetail.FirstOrDefault(t => t.productInstockId == wmsProductInstock.productInstockId); + // if (wmsProductInstockDetail != null) + // { + MesBasePalletInfo? mesBasePalletInfo = dbContext.MesBasePalletInfo.FirstOrDefault(t => t.palletInfoCode == item.containerNo); + if (mesBasePalletInfo != null) + { + MesBaseBarcodeInfo? mesBaseBarcodeInfo = dbContext.MesBaseBarcodeInfo.FirstOrDefault(t => t.palletInfoCode == item.containerNo); + if (mesBaseBarcodeInfo != null) + { + WmsBaseLocation wmsBaseLocation = dbContext.WmsBaseLocation.First(t => t.locationId == item.endPointId); + wmsBaseLocation.locationStatus = "1"; + wmsBaseLocation.containerCode = item.containerNo; + WmsProductStock wmsProductStock = new WmsProductStock() + { + productId = mesBasePalletInfo.materialId, + activeFlag = "1", + frozenAmount = 0, + createBy = "WCS", + createDate = DateTime.Now, + updateBy = "WCS", + updateDate = DateTime.Now, + instockDate = DateTime.Now, + locationCode = wmsBaseLocation.locationCode, + occupyAmount = 0, + totalAmount = 1, + palletInfoCode = item.containerNo, + planCode = StaticData.SnowId.NextId().ToString(), + planDetailCode = mesBaseBarcodeInfo.planDetailCode, + productBatch = mesBasePalletInfo.materialBarcode, + saleorderCode = mesBaseBarcodeInfo.saleorderCode, + productStockId = StaticData.SnowId.NextId(), + saleOrderId = mesBaseBarcodeInfo.saleOrderId, + stockType = "3", + qualityStatus = "0", + warehouseFloor = 2, + warehouseId = wmsBaseLocation.warehouseId + }; + + #region 插入WmsProductInstock表 + + WmsProductInstock wmsProductInstock = new WmsProductInstock(); + wmsProductInstock.taskCode = StaticData.SnowId.NextId().ToString(); + wmsProductInstock.warehouseId = wmsBaseLocation.warehouseId; + wmsProductInstock.warehouseFloor = 2; + wmsProductInstock.locationCode = wmsBaseLocation.locationCode; + wmsProductInstock.productType = "3"; + wmsProductInstock.operationType = "3"; + wmsProductInstock.planCode = StaticData.SnowId.NextId().ToString(); + wmsProductInstock.planDetailCode = mesBaseBarcodeInfo.planDetailCode; + wmsProductInstock.SaleOrderId = mesBaseBarcodeInfo.saleOrderId; + wmsProductInstock.saleorderCode = mesBaseBarcodeInfo.saleorderCode; + wmsProductInstock.instockType = "1"; + wmsProductInstock.productId = mesBaseBarcodeInfo.materialId; + wmsProductInstock.productBatch = mesBaseBarcodeInfo.barcodeInfo; + wmsProductInstock.instockAmount = mesBaseBarcodeInfo.amount; + wmsProductInstock.palletInfoCode = mesBaseBarcodeInfo.palletInfoCode; + wmsProductInstock.auditStatus = "1"; + wmsProductInstock.executeStatus = "2"; + wmsProductInstock.applyBy = "WCS"; + wmsProductInstock.applyDate = DateTime.Now; + wmsProductInstock.updateBy = "WCS"; + wmsProductInstock.updateDate = DateTime.Now; + wmsProductInstock.beginTime = DateTime.Now; + wmsProductInstock.endTime = DateTime.Now; + dbContext.Add(wmsProductInstock); + + #endregion 插入WmsProductInstock表 + + //wmsProductInstockDetail.executeStatus = "2"; + //wmsProductInstock.endTime = DateTime.Now; + //wmsProductInstock.executeStatus = "2"; + //dbContext.Update(wmsProductInstockDetail); + dbContext.Add(wmsProductStock); + SystemData.UnLockOutLocation(wmsBaseLocation, dbContext); + dbContext.Update(wmsBaseLocation); + //dbContext.Update(wmsProductInstock); + dbContext.Remove(item); + dbContext.WcsTaskLog.Where(t => t.objid == item.objid).Update(t => new WcsTaskLog() { taskStatus = 8 }); + dbContext.SaveChanges(); + _logger.Info("二楼AGV线程完成任务" + item.objid); + SystemData.SendPlcLocation(wmsBaseLocation); + } + // } + //} + } + } + else if (item.taskType == StaticTaskType.SecondStorageToLift)//成品出库 + { + WmsProductOutstock? wmsProductOutstock = dbContext.WmsProductOutstock.FirstOrDefault(t => t.productOutstockId == item.orderId); + if (wmsProductOutstock != null) + { + var wmsBaseLocation = dbContext.WmsBaseLocation.Where(t => t.locationId == item.currPointId).First(); + WmsProductStock wmsProductStock = dbContext.WmsProductStock.First(t => t.locationCode == wmsBaseLocation.locationCode); + + wmsProductOutstock.outstockQty++; + if (wmsProductOutstock.applyQty <= wmsProductOutstock.outstockQty) + { + wmsProductOutstock.endTime = DateTime.Now; + wmsProductOutstock.executeStatus = "2"; + } + WmsProductOutstockDetail? wmsProductOutstockDetail = dbContext.WmsProductOutstockDetail.FirstOrDefault(x => x.productOutstockId == wmsProductOutstock.productOutstockId && x.locationCode == item.currPointId.ToString()); + if (wmsProductOutstockDetail != null) + { //人工出库,mes会自动插入,wcs只需要更新即可 + wmsProductOutstockDetail.outstockAmount = 1; + wmsProductOutstockDetail.executeStatus = "2"; + wmsProductOutstockDetail.updateDate = DateTime.Now; + wmsProductOutstockDetail.endTime = DateTime.Now; + dbContext.Update(wmsProductOutstockDetail); + } + else + { + wmsProductOutstockDetail = new WmsProductOutstockDetail(); + wmsProductOutstockDetail.productOutstockId = wmsProductOutstock.productOutstockId; + wmsProductOutstockDetail.warehouseId = wmsProductOutstock.warehouseId; + wmsProductOutstockDetail.locationCode = wmsBaseLocation.locationCode; + wmsProductOutstockDetail.productBarcode = wmsProductStock.productBatch; + wmsProductOutstockDetail.productId = wmsProductStock.productId; + wmsProductOutstockDetail.planAmount = wmsProductOutstock.applyQty; + wmsProductOutstockDetail.outstockAmount = 1; + wmsProductOutstockDetail.executeStatus = "2"; + wmsProductOutstockDetail.updateBy = "WCS"; + wmsProductOutstockDetail.updateDate = DateTime.Now; + wmsProductOutstockDetail.beginTime = DateTime.Now; + wmsProductOutstockDetail.endTime = DateTime.Now; + dbContext.Add(wmsProductOutstockDetail); + } + + wmsBaseLocation.locationStatus = "1"; + wmsBaseLocation.containerCode = null; + item.nextPointId = 2; + item.taskStatus = 8; + SystemData.UnLockOutLocation(wmsBaseLocation, dbContext); + dbContext.Remove(wmsProductStock); + dbContext.Update(wmsBaseLocation); + + dbContext.Update(wmsProductOutstock); + dbContext.Update(item); + dbContext.WcsTaskLog.Where(t => t.objid == item.objid).Update(t => new WcsTaskLog() { taskStatus = 8 }); + dbContext.SaveChanges(); + _logger.Info("二楼AGV线程完成任务" + item.objid); + SystemData.SendPlcLocation(wmsBaseLocation); + } + } + else if (item.taskType == StaticTaskType.SecondLiftToTransit)//空托盘入周转位 + { + BaseEquip endEquip = StaticData.BaseEquip.First(t => t.objid == item.endPointId); + endEquip.equipStatus = 1; + endEquip.emptyCount = item.qty; + endEquip.ud3 = "1"; + dbContext.Update(endEquip); + dbContext.Remove(item); + dbContext.WcsTaskLog.Where(t => t.objid == item.objid).Update(t => new WcsTaskLog() { taskStatus = 8 }); + dbContext.SaveChanges(); + _logger.Info("二楼AGV线程完成任务" + item.objid); + } + else if (item.taskType == StaticTaskType.SecondLiftToWaste)//提升机到废料口 + { + BaseEquip startEquip = dbContext.BaseEquip.First(t => t.objid == item.currPointId); + startEquip.equipStatus = 0; + BaseEquip endEquip = StaticData.BaseEquip.First(t => t.objid == item.endPointId); + endEquip.equipStatus = 1; + endEquip.emptyCount = 1; + endEquip.containerNo = item.containerNo; + endEquip.ud3 = "2"; + dbContext.Update(endEquip); + dbContext.Update(startEquip); + dbContext.Remove(item); + dbContext.WcsTaskLog.Where(t => t.objid == item.objid).Update(t => new WcsTaskLog() { taskStatus = 8 }); + dbContext.SaveChanges(); + _logger.Info("二楼AGV线程完成任务" + item.objid); + } + else if (item.taskType == StaticTaskType.SecondLineToSmallPackage)//输送线到小包入口 + { + Task.Run(() => + { + Thread.Sleep(3000); + // 小包入口放料完成确认信号 + //放托盘确认信号DB4.DBX310.0写true + BasePlcpoint SecondInPutOverPoint = StaticData.BasePlcpointList.First(t => t.id == 72); + StaticData.PlcDic[2].WriteToPoint(SecondInPutOverPoint.plcpointAddress, true, SecondInPutOverPoint.plcpointLength.ToString()); + }); + + BaseEquip startEquip = dbContext.BaseEquip.First(t => t.objid == item.currPointId); + startEquip.equipStatus = 0; + dbContext.Update(startEquip); + dbContext.Remove(item); + dbContext.WcsTaskLog.Where(t => t.objid == item.objid).Update(t => new WcsTaskLog() { taskStatus = 8 }); + dbContext.SaveChanges(); + _logger.Info("二楼AGV线程完成任务" + item.objid); + } + else if (item.taskType == StaticTaskType.SecondTransitToWaste)//周转位到废料口 + { + BaseEquip startEquip = StaticData.BaseEquip.First(t => t.objid == item.currPointId); + startEquip.equipStatus = 0; + startEquip.emptyCount = 0; + startEquip.ud3 = "0"; + startEquip.containerNo = null; + BaseEquip endEquip = StaticData.BaseEquip.First(t => t.objid == item.endPointId); + endEquip.equipStatus = 1; + endEquip.emptyCount = 1; + endEquip.containerNo = item.containerNo; + endEquip.ud3 = "2"; + dbContext.Update(startEquip); + dbContext.Update(endEquip); + dbContext.Remove(item); + dbContext.WcsTaskLog.Where(t => t.objid == item.objid).Update(t => new WcsTaskLog() { taskStatus = 8 }); + dbContext.SaveChanges(); + _logger.Info("二楼AGV线程完成任务" + item.objid); + } + else if (item.taskType == StaticTaskType.SecondRemove)//移库 + { + var wmsProductStock = dbContext.WmsProductStock.FirstOrDefault(t => t.locationCode == item.currPointNo); + WmsBaseLocation wmsBaseLocation = dbContext.WmsBaseLocation.Where(t => t.locationId == item.currPointId).First(); + WmsBaseLocation toLocation = dbContext.WmsBaseLocation.Where(t => t.locationId == item.endPointId).First(); + dbContext.WmsBaseLocation.Where(t => t.locationId == wmsBaseLocation.locationId) + .Update(t => new WmsBaseLocation() { containerCode = null, updateTime = DateTime.Now, locationStatus = "1" }); + dbContext.WmsBaseLocation.Where(t => t.locationId == toLocation.locationId) + .Update(t => new WmsBaseLocation { containerCode = item.containerNo, updateTime = DateTime.Now, locationStatus = "1" }); + + SystemData.UnLockOutLocation(wmsBaseLocation, dbContext); + SystemData.UnLockOutLocation(toLocation, dbContext); + if (wmsProductStock != null) + { + wmsProductStock.locationCode = item.endPointNo; + dbContext.Update(wmsProductStock); + } + dbContext.Remove(item); + dbContext.WcsTaskLog.Where(t => t.objid == item.objid).Update(t => new WcsTaskLog() { taskStatus = 8 }); + + #region 插入移库记录 + + var wmsMove = dbContext.WmsMove.Where(t => t.MoveId == item.orderId).FirstOrDefault(); + if (wmsMove == null) + { + wmsMove = new WmsMove(); + wmsMove.MoveId = StaticData.SnowId.NextId(); + wmsMove.TaskCode = StaticData.SnowId.NextId().ToString(); + wmsMove.WarehouseId = wmsBaseLocation.warehouseId; + wmsMove.OriLocationCode = wmsBaseLocation.locationCode; + wmsMove.TargetLocationCode = toLocation.locationCode; + wmsMove.InstockBatch = wmsProductStock.productBatch; + wmsMove.MaterialId = wmsProductStock.productId; + wmsMove.PlanAmount = 1; + wmsMove.RealOutstockAmount = 1; + wmsMove.RealInstockAmount = 1; + wmsMove.OperationType = "3"; + wmsMove.MoveWay = "2"; + wmsMove.MoveType = "1"; + wmsMove.AuditStatus = "1"; + wmsMove.ExecuteStatus = "2"; + wmsMove.UpdateBy = "WCS"; + wmsMove.UpdateDate = DateTime.Now; + wmsMove.BeginTime = DateTime.Now; + wmsMove.EndTime = DateTime.Now; + dbContext.WmsMove.Add(wmsMove); + } + else + { + wmsMove.RealOutstockAmount += 1; + wmsMove.EndTime = DateTime.Now; + wmsMove.UpdateDate = DateTime.Now; + wmsMove.UpdateBy = "WCS"; + wmsMove.ExecuteStatus = "2"; + dbContext.Update(wmsMove); + } + WmsMoveDetail wmsMoveDetail = new WmsMoveDetail(); + wmsMoveDetail.MoveId = wmsMove.MoveId; + wmsMoveDetail.MaterialBarcode = wmsMove.InstockBatch; + wmsMoveDetail.InstockBatch = wmsMove.InstockBatch; + wmsMoveDetail.MaterialId = (long)wmsProductStock.productId; + wmsMoveDetail.LocationCode = toLocation.locationCode; + wmsMoveDetail.PlanAmount = 1; + wmsMoveDetail.RealInstockAmount = 1; + wmsMoveDetail.RealAmount = 1; + wmsMoveDetail.ExecuteStatus = "2"; + wmsMoveDetail.ExecuteTime = DateTime.Now; + wmsMoveDetail.ExecuteEndTime = DateTime.Now; + wmsMoveDetail.ExecutePerson = "WCS"; + wmsMoveDetail.UpdateBy = "WCS"; + wmsMoveDetail.UpdateDate = DateTime.Now; + + dbContext.WmsMoveDetail.Add(wmsMoveDetail); + + #endregion 插入移库记录 + + dbContext.SaveChanges(); + SystemData.SendPlcLocation(wmsBaseLocation); + SystemData.SendPlcLocation(toLocation); + + _logger.Info("二楼AGV线程完成任务" + item.objid); + } + else if (item.taskType == StaticTaskType.SecondWasteToTransit)//废料区到周转区 + { + wasteEquip.emptyCount = 0; + wasteEquip.equipStatus = 0; + wasteEquip.ud3 = "0"; + BaseEquip endEquip = dbContext.BaseEquip.First(t => t.objid == item.endPointId); + endEquip.emptyCount = 1; + endEquip.equipStatus = 1; + endEquip.ud3 = "2"; + endEquip.containerNo = item.containerNo; + dbContext.Remove(item); + dbContext.Update(wasteEquip); + dbContext.WcsTaskLog.Where(t => t.objid == item.objid).Update(t => new WcsTaskLog() { taskStatus = 8 }); + dbContext.SaveChanges(); + _logger.Info("二楼AGV线程完成任务" + item.objid); + } + else if (item.taskType == StaticTaskType.SecondTransitToLift)//周转位-提升机 + { + BaseEquip emptyEquip = StaticData.BaseEquip.First(t => t.objid == item.currPointId); + emptyEquip.emptyCount = 0; + emptyEquip.equipStatus = 0; + emptyEquip.ud3 = "0"; + emptyEquip.containerNo = null; + item.nextPointId = 2; + item.taskStatus = 8; + dbContext.Update(item); + dbContext.Update(emptyEquip); + dbContext.WcsTaskLog.Where(t => t.objid == item.objid).Update(t => new WcsTaskLog() { taskStatus = 6 }); + dbContext.SaveChanges(); + _logger.Info("二楼AGV线程完成任务" + item.objid); + } + else if (item.taskType == StaticTaskType.SecondTransitToSmallPackage)//周转区-小包入口 + { + BaseEquip startEquip = StaticData.BaseEquip.First(t => t.objid == item.currPointId); + startEquip.equipStatus = 0; + startEquip.emptyCount = 0; + startEquip.ud3 = "0"; + startEquip.containerNo = null; + dbContext.Update(startEquip); + dbContext.Remove(item); + dbContext.WcsTaskLog.Where(t => t.objid == item.objid).Update(t => new WcsTaskLog() { taskStatus = 8 }); + dbContext.SaveChanges(); + _logger.Info("二楼AGV线程完成任务" + item.objid); + } + } + } + break; + } + } + catch (Exception ex) + { + if (ex is PlcException) + { + } + else + { + _logger.Error(ex.Message + "\n" + ex.StackTrace); + } + } + finally + { + Thread.Sleep(1000); + } + } + } + } +} \ No newline at end of file diff --git a/src/Khd.Core.Wcs/Wcs/SecondFloorLine.cs b/src/Khd.Core.Wcs/Wcs/SecondFloorLine.cs new file mode 100644 index 0000000..0ba06a9 --- /dev/null +++ b/src/Khd.Core.Wcs/Wcs/SecondFloorLine.cs @@ -0,0 +1,408 @@ +using Khd.Core.Domain.Dto.TaskType; +using Khd.Core.Domain.Dto.waring; +using Khd.Core.Domain.Models; +using Khd.Core.EntityFramework; +using Khd.Core.Library; +using Khd.Core.Library.Mapper; +using Khd.Core.Plc.S7; +using Khd.Core.Wcs.Global; +using Masuit.Tools; +using Microsoft.EntityFrameworkCore; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; + +namespace Khd.Core.Wcs.Wcs +{ + /// + /// 二楼小包出入口 + /// + public class SecondFloorLine + { + private readonly LoggerUtils _logger = new LoggerUtils(); + private readonly IHost _host; + private int FloorNo { get; set; } + + public SecondFloorLine(IHost host, int floor) + { + this._host = host; + FloorNo = floor; + } + + /// + /// 启动上件扫描监听 + /// + public void StartPoint() + { + Thread FlowPointThread = new Thread(MonitorInLocatorPoint); + FlowPointThread.IsBackground = true; + FlowPointThread.Name = "SecondFloorLine"; + FlowPointThread.Start(); + Console.WriteLine(DateTime.Now + ":二楼码垛输送线调度启动成功"); + _logger.Info("二楼码垛输送线调度启动成功"); + } + + public void MonitorInLocatorPoint() + { + using var scope = _host.Services.CreateScope(); + using var dbContext = scope.ServiceProvider.GetRequiredService(); + var rfidPoint = StaticData.BasePlcpointList.First(t => t.id == 52); + var agvGetPoint = StaticData.BasePlcpointList.First(t => t.id == 53); + // 托盘库叫料信号 + var agvPutPoint = StaticData.BasePlcpointList.First(t => t.id == 54); + //2F托盘库产线数据通讯情况 + var ConnectStatus2FPoint = StaticData.BasePlcpointList.First(t => t.id == 73); + //2F托盘库入口上料光电 + var PalletInIsHas2FPoint = StaticData.BasePlcpointList.First(t => t.id == 74); + + BaseEquip agvEquip = StaticData.BaseEquip.First(t => t.objid == 8); + BaseEquip endEquip = StaticData.BaseEquip.First(t => t.objid == 36); + List canNotIn = new List(); + while (true) + { + try + { + dbContext.ChangeTracker.Clear(); + var agvPutValue = StaticData.PlcDic[2].Read(agvPutPoint.plcpointAddress);//托盘库叫料信号 + var ConnectStatus2F = StaticData.PlcDic[2].Read(ConnectStatus2FPoint.plcpointAddress);//2F托盘库产线数据通讯情况 + var PalletInIsHas2F = StaticData.PlcDic[2].Read(PalletInIsHas2FPoint.plcpointAddress);//2F托盘库入口上料光电 + + var agvGetValue = StaticData.PlcDic[2].Read(agvGetPoint.plcpointAddress);//小包出口的到位 + var rfidValue = StaticData.PlcDic[2].ReadRFID(rfidPoint.plcpointAddress, 15);//小包出口的RFID + if (agvGetValue != null && agvPutValue != null && rfidValue != null && ConnectStatus2F != null && PalletInIsHas2F != null)//读Plc + { + // 托盘库叫料信号,并且通讯正常,并且小包入口无料才可叫料 + if (Convert.ToInt32(agvPutValue) == 1 && Convert.ToInt32(ConnectStatus2F) == 1 && Convert.ToInt32(PalletInIsHas2F) == 0)//小包入口叫料 + { + bool canCreate = dbContext.WcsTask.Where(t => t.nextPointId == 8 || t.endPointId == endEquip.objid).Any();//有没有生成任务 + //36 是小包入口的设备信息,8是二楼Agv设备 + if (!canCreate)//没有任务 + { + //间隔20分钟以下,禁止再次生成空托盘配送到小包入口任务 + bool hasHistoryTask = dbContext.WcsTaskLog.Where(t => t.endPointNo == endEquip.equipNo && t.createTime >= DateTime.Now.AddMinutes(-20)).Any(); + if (hasHistoryTask) + { + //20分钟内已经生成过任务 + continue; + } + + BaseEquip? baseEquip = dbContext.BaseEquip.FirstOrDefault(t => t.equipType == 20 && t.emptyCount >= 1);//二楼周转区是否存在一个空托盘以上的 + if (baseEquip != null)//二楼周转区有可以去小包入口的库位 + { + var wcsTask = new WcsTask() + { + objid = StaticData.SnowId.NextId(), + endPointId = endEquip.objid,//小包入口 + endPointNo = endEquip.equipNo, + nextPointId = agvEquip.objid,//二楼叉车 + nextPointNo = agvEquip.equipNo, + currPointId = baseEquip.objid,//周转区库位 + currPointNo = baseEquip.equipNo, + taskStatus = 0, + useFlag = 1, + containerNo = null, + createBy = "WCS", + createTime = DateTime.Now, + floorNo = 2, + fromFloorNo = 2, + isEmpty = "1", + qty = baseEquip.emptyCount,//托盘的数量 + taskType = StaticTaskType.SecondTransitToSmallPackage,//任务类型 + }; + dbContext.Add(wcsTask); + WcsTaskLog wcsTaskLog = CoreMapper.Map(wcsTask); + dbContext.Add(wcsTaskLog); + dbContext.SaveChanges(); + Console.WriteLine(DateTime.Now + ":二楼码垛输送线生成请求空托盘任务成功:" + wcsTask.objid); + _logger.Info("二楼码垛输送线生成请求空托盘任务成功:" + wcsTask.objid); + } + else//二楼周转区没有空托盘 + { + baseEquip = dbContext.BaseEquip.FirstOrDefault(t => t.equipType == 15 && t.emptyCount == SystemData.maxTray);//三楼三个周转区是否存在空托盘 + if (baseEquip != null)//如果三楼有空托盘 + { + BaseEquip ThirdLineEquip = dbContext.BaseEquip.First(t => t.objid == 3);//三楼接驳位 + BaseEquip ThirdAgvEquip = StaticData.BaseEquip.First(t => t.objid == 9);//三楼叉车 + if (ThirdLineEquip.equipStatus == 0)//三楼接驳位空闲 + { + //生成3楼Agv出库任务 + WcsTask wcsTask = new WcsTask() + { + objid = StaticData.SnowId.NextId(), + containerNo = null, + createBy = "WCS", + createTime = DateTime.Now, + floorNo = 2, + fromFloorNo = 3, + isEmpty = "1", + qty = SystemData.maxTray, + taskType = StaticTaskType.ThirdTransitToSecond, + currPointId = baseEquip.objid, + currPointNo = baseEquip.equipNo, + nextPointId = ThirdAgvEquip.objid, + nextPointNo = ThirdAgvEquip.equipNo, + endPointId = endEquip.objid, + endPointNo = endEquip.equipNo, + taskStatus = 0, + useFlag = 1, + }; + dbContext.Add(wcsTask); + WcsTaskLog wcsTaskLog = CoreMapper.Map(wcsTask); + dbContext.Add(wcsTaskLog); + dbContext.SaveChanges(); + Console.WriteLine(DateTime.Now + ":二楼码垛输送线生成3楼Agv出库任务成功:" + wcsTask.objid); + _logger.Info("二楼码垛输送线生成3楼Agv出库任务成功:" + wcsTask.objid); + } + } + else + { + BaseEquip startEquip = dbContext.BaseEquip.First(t => t.objid == 40);//一楼的托盘库 + if (startEquip.emptyCount > 1 && startEquip.emptyCount <= SystemData.maxTray) + { + BasePlcpoint basePlcpoint = StaticData.BasePlcpointList.First(t => t.plcpointNo == "someOut");//多个出 + BasePlcpoint linesignal01 = StaticData.BasePlcpointList.First(t => t.plcpointNo == "linesignal01");//一楼接驳位到位 + BasePlcpoint equipstate06 = StaticData.BasePlcpointList.First(t => t.plcpointNo == "equipstate06");//提升机状态 + BasePlcpoint trayStatusValue = StaticData.BasePlcpointList.First(t => t.plcpointNo == "trayStatus");//提升机状态 + BaseEquip lineEquip = dbContext.BaseEquip.First(t => t.objid == 1);//一楼接驳位 + var lineSignal01Value = StaticData.PlcDic[0].Read(linesignal01.plcpointAddress); + var equipstate06Value = StaticData.PlcDic[0].Read(equipstate06.plcpointAddress); + if (FirstFloor.ReadEmptyLocation() && trayStatusValue != null && Convert.ToInt32(trayStatusValue) == 1 && Convert.ToInt32(lineSignal01Value) == 0 && Convert.ToInt32(equipstate06Value) == 0) + { + StaticData.PlcDic[0].WriteToPoint(basePlcpoint.plcpointAddress, "1", basePlcpoint.plcpointLength.ToString());//托盘库多个出 + WcsTask wcsTaskManual = new WcsTask() + { + objid = StaticData.SnowId.NextId(), + endPointId = endEquip.objid, + endPointNo = endEquip.equipNo, + nextPointId = lineEquip.objid, + nextPointNo = lineEquip.equipNo, + currPointId = lineEquip.objid, + currPointNo = lineEquip.equipNo, + taskStatus = 0, + useFlag = 1, + containerNo = null, + createBy = "WCS", + createTime = DateTime.Now, + floorNo = endEquip.floorNo, + fromFloorNo = 1, + isEmpty = "1", + qty = startEquip.emptyCount, + taskType = StaticTaskType.SecondLiftToWaste, + }; + dbContext.Add(wcsTaskManual); + WcsTaskLog wcsTaskLog = CoreMapper.Map(wcsTaskManual); + dbContext.Add(wcsTaskLog); + dbContext.SaveChanges(); + Console.WriteLine(DateTime.Now + ":二楼码垛输送线生成手动托盘任务成功:" + wcsTaskManual.objid); + _logger.Info("二楼码垛输送线生成手动托盘任务成功:" + wcsTaskManual.objid); + } + } + else if (startEquip.emptyCount > SystemData.maxTray)//如果托盘库大于五个,出一个 + { + BasePlcpoint basePlcpoint = StaticData.BasePlcpointList.First(t => t.plcpointNo == "oneOut");//多个出 + BasePlcpoint linesignal01 = StaticData.BasePlcpointList.First(t => t.plcpointNo == "linesignal01");//一楼接驳位到位 + BasePlcpoint equipstate06 = StaticData.BasePlcpointList.First(t => t.plcpointNo == "equipstate06");//提升机状态 + BasePlcpoint trayStatusValue = StaticData.BasePlcpointList.First(t => t.plcpointNo == "trayStatus");//提升机状态 + BaseEquip lineEquip = dbContext.BaseEquip.First(t => t.objid == 1);//一楼接驳位 + var lineSignal01Value = StaticData.PlcDic[0].Read(linesignal01.plcpointAddress); + var equipstate06Value = StaticData.PlcDic[0].Read(equipstate06.plcpointAddress); + if (FirstFloor.ReadEmptyLocation() && trayStatusValue != null && Convert.ToInt32(trayStatusValue) == 1 && Convert.ToInt32(lineSignal01Value) == 0 && Convert.ToInt32(equipstate06Value) == 0) + { + StaticData.PlcDic[0].WriteToPoint(basePlcpoint.plcpointAddress, "1", basePlcpoint.plcpointLength.ToString());//托盘库多个出 + WcsTask wcsTaskManual = new WcsTask() + { + objid = StaticData.SnowId.NextId(), + endPointId = endEquip.objid, + endPointNo = endEquip.equipNo, + nextPointId = lineEquip.objid, + nextPointNo = lineEquip.equipNo, + currPointId = lineEquip.objid, + currPointNo = lineEquip.equipNo, + taskStatus = 0, + useFlag = 1, + containerNo = null, + createBy = "WCS", + createTime = DateTime.Now, + floorNo = endEquip.floorNo, + fromFloorNo = 1, + isEmpty = "1", + qty = 1, + taskType = StaticTaskType.SecondLiftToWaste, + }; + dbContext.Add(wcsTaskManual); + WcsTaskLog wcsTaskLog = CoreMapper.Map(wcsTaskManual); + dbContext.Add(wcsTaskLog); + dbContext.SaveChanges(); + Console.WriteLine(DateTime.Now + ":二楼码垛输送线生成手动托盘任务成功:" + wcsTaskManual.objid); + _logger.Info("二楼码垛输送线生成手动托盘任务成功:" + wcsTaskManual.objid); + } + } + else + { + //todo:没有空托盘超过十次预警报警 + Console.WriteLine(DateTime.Now + ":二楼码垛输送线没有空托盘,叫托盘失败!"); + _logger.Info("二楼码垛输送线没有空托盘,叫托盘失败!"); + Thread.Sleep(1000 * 5); + } + } + } + } + } + if (Convert.ToInt32(agvGetValue) == 1 && !string.IsNullOrEmpty(rfidValue))//小包出口成品入口 + { + bool canCreate = dbContext.WcsTask.Where(t => t.nextPointId == 8).Any();//有没有生成任务 + if (!canCreate) + { + lock (SystemData.SecondTaskLock) + { + MesBasePalletInfo? mesBasePalletInfo = dbContext.MesBasePalletInfo.FirstOrDefault(t => t.palletInfoCode == rfidValue); + if (mesBasePalletInfo != null) + { + MesBaseBarcodeInfo? mesBaseBarcodeInfo = dbContext.MesBaseBarcodeInfo.FirstOrDefault(t => t.barcodeInfo == mesBasePalletInfo.materialBarcode); + if (mesBaseBarcodeInfo != null) + { + // 目标库位 + WmsBaseLocation? wmsBaseLocation = null; + var wmsBaseLocations = dbContext.WmsBaseLocation + .Where(t => t.warehouseFloor == FloorNo) + .Where(t => t.activeFlag == "1") + .Where(t => t.delFlag == "0") + .Where(t => t.locationScrapType == "1") + .Where(t => t.locationStatus == "1") + .Where(t => t.warehouseId == 231) + .ToList();//所有未锁定的库位 + + //深库位有库存的库位 + List DeepContainerCodes = wmsBaseLocations + .Where(t => t.locDeep == 1) + .Where(t => !string.IsNullOrEmpty(t.containerCode)) + .Select(t => t.containerCode).ToList(); + + //相同型号及销售订单的深库位库存 + List productStocks = dbContext.WmsProductStock.Where(t => t.productId == mesBaseBarcodeInfo.materialId) + .Where(t => t.saleOrderId == mesBaseBarcodeInfo.saleOrderId) + .Where(t => t.warehouseId == 231) + .Where(t => DeepContainerCodes.Contains(t.palletInfoCode)).ToList(); + + if (productStocks.Count > 0) + { //优先找同销售订单的有库存的深库位对应的浅库位 + foreach (var productStock in productStocks) + { + // 深库位库存对用的Location信息 + var deepStockLocation = wmsBaseLocations.Where(t => t.containerCode == productStock.palletInfoCode).FirstOrDefault(); + wmsBaseLocation = wmsBaseLocations.Where(t => string.IsNullOrEmpty(t.containerCode) && t.locationStatus == "1") + .Where(t => t.locDeep == 2 && t.locColumn == deepStockLocation.locColumn) + .Where(t => t.locRow == (deepStockLocation.locRow % 2 == 0 ? (deepStockLocation.locRow - 1) : (deepStockLocation.locRow + 1))) + .FirstOrDefault(); + if (wmsBaseLocation != null) + { + break; + } + } + } + //if(wmsBaseLocation == null) + //{ // 找深库位有库存的库位对应的浅库位 + // var stockLocations = wmsBaseLocations.Where(x => !string.IsNullOrEmpty(x.containerCode) && x.locDeep==1).ToList(); + // foreach (var item in stockLocations) + // { + // wmsBaseLocation = wmsBaseLocations.Where(t => string.IsNullOrEmpty(t.containerCode) && t.locationStatus == "1") + // .Where(t => t.locDeep == 2 && t.locColumn == item.locColumn) + // .Where(t => t.locRow == (item.locRow % 2 == 0 ? (item.locRow - 1) : (item.locRow + 1))) + // .FirstOrDefault(); + // if (wmsBaseLocation != null) + // { + // break; + // } + // } + //} + if (wmsBaseLocation == null) + { // 在所有符合条件的库位里,找一个库位,优先深库位,但是如果是深库位,需要判断浅库位状态是否正常 + var searchLocations = wmsBaseLocations.Where(x => string.IsNullOrEmpty(x.containerCode) && x.locationStatus == "1").OrderBy(x => x.locDeep).ToList(); + foreach (var item in searchLocations) + { + if (item.locDeep == 1) + { + //浅库位能否使用 + var shallowLocation = wmsBaseLocations.Where(t => string.IsNullOrEmpty(t.containerCode) && t.locationStatus == "1") + .Where(t => t.locDeep == 2 && t.locColumn == item.locColumn) + .Where(t => t.locRow == (item.locRow % 2 == 0 ? (item.locRow - 1) : (item.locRow + 1))) + .FirstOrDefault(); + if (shallowLocation != null) + { + wmsBaseLocation = item; + break; + } + } + else + { + wmsBaseLocation = item; + break; + } + } + } + + if (wmsBaseLocation != null)//如果找到库位,生成入库任务 + { + BaseEquip startEquip = StaticData.BaseEquip.First(t => t.objid == 37); + var wcsTask = new WcsTask() + { + objid = StaticData.SnowId.NextId(), + currPointId = startEquip.objid, + currPointNo = startEquip.equipNo, + nextPointId = agvEquip.objid, + nextPointNo = agvEquip.equipNo, + endPointId = wmsBaseLocation.locationId, + endPointNo = wmsBaseLocation.locationCode, + taskStatus = 0, + useFlag = 1, + containerNo = rfidValue, + createBy = "WCS", + createTime = DateTime.Now, + floorNo = 2, + fromFloorNo = 2, + isEmpty = "0", + taskType = StaticTaskType.SecondSmallPackageToStorage, + qty = 1, + }; + SystemData.LockOutLocation(wmsBaseLocation, dbContext); + dbContext.Add(wcsTask); + WcsTaskLog wcsTaskLog = CoreMapper.Map(wcsTask); + dbContext.Add(wcsTaskLog); + SystemData.DeleteWaringLog(dbContext, WaringType.二楼入库任务创建失败); + dbContext.SaveChanges(); + canNotIn.Clear(); + Console.WriteLine(DateTime.Now + ":二楼码垛输送线生成入库托盘任务成功:" + wcsTask.objid); + _logger.Info("二楼码垛输送线生成入库托盘任务成功:" + wcsTask.objid); + } + else + { + Console.WriteLine(DateTime.Now + ":2楼调度入库任务,未找到库位"); + _logger.Info("2楼调度入库任务,未找到库位"); + SystemData.InsertWaringLog(dbContext, WaringType.二楼入库任务创建失败); + // TODO: 没有找到库位,添加报警处理 + Thread.Sleep(1000 * 5); + } + } + } + } + } + } + } + } + catch (Exception ex) + { + if (ex is PlcException) + { + } + else + { + _logger.Error(ex.Message + "\n" + ex.StackTrace); + } + } + finally + { + Thread.Sleep(1000); + } + } + } + } +} \ No newline at end of file diff --git a/src/Khd.Core.Wcs/Wcs/SecondFloorPoint.cs b/src/Khd.Core.Wcs/Wcs/SecondFloorPoint.cs new file mode 100644 index 0000000..18ce440 --- /dev/null +++ b/src/Khd.Core.Wcs/Wcs/SecondFloorPoint.cs @@ -0,0 +1,349 @@ +using Khd.Core.Domain.Dto.TaskType; +using Khd.Core.Domain.Models; +using Khd.Core.EntityFramework; +using Khd.Core.Library; +using Khd.Core.Library.Mapper; +using Khd.Core.Plc.S7; +using Khd.Core.Wcs.Global; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; + +namespace Khd.Core.Wcs.Wcs +{ + /// + /// 二楼接驳位调度 + /// + public class SecondFloorPoint + { + private readonly LoggerUtils _logger = new LoggerUtils(); + private readonly IHost _host; + private readonly BasePlcpoint LineRFID; + private readonly BasePlcpoint LineSignal; + int FloorNo { get; set; } + public SecondFloorPoint(IHost host, int floor) + { + this._host = host; + FloorNo = floor; + this.LineRFID = StaticData.BasePlcpointList.First(t => t.plcpointNo == "RFID002"); + this.LineSignal = StaticData.BasePlcpointList.First(t => t.plcpointNo == "linesignal02"); + } + /// + /// 启动上件扫描监听 + /// + public void StartPoint() + { + + Thread FlowPointThread = new Thread(MonitorInLocatorPoint); + FlowPointThread.Name = "SecondFloorPoint"; + FlowPointThread.IsBackground = true; + FlowPointThread.Start(); + Console.WriteLine(DateTime.Now + ":二楼接驳位扫描线程启动"); + _logger.Info("二楼接驳位扫描线程启动"); + } + + public void MonitorInLocatorPoint() + { + using var scope = _host.Services.CreateScope(); + using var dbContext = scope.ServiceProvider.GetRequiredService(); + BaseEquip inEquip = StaticData.BaseEquip.First(t => t.objid == 36);//小包入口 + BaseEquip outEquip = StaticData.BaseEquip.First(t => t.objid == 37);//小包出口 + BaseEquip lineEquip = StaticData.BaseEquip.First(t => t.objid == 2);//二楼接驳位 + BaseEquip agvEquip = StaticData.BaseEquip.First(t => t.objid == 8);//二楼叉车 + BaseEquip tsjEquip = StaticData.BaseEquip.First(t => t.objid == 6);//提升机 + var PalletInIsHas2FPoint = StaticData.BasePlcpointList.First(t => t.id == 74); + var agvPutPoint = StaticData.BasePlcpointList.First(t => t.id == 54);//二楼小包入口点位 + var ConnectStatus2FPoint = StaticData.BasePlcpointList.First(t => t.id == 73); + while (true) + { + try + { + dbContext.ChangeTracker.Clear(); + //入库任务 + var rfid = StaticData.PlcDic[0].ReadRFID(LineRFID.plcpointAddress); + //2F托盘库产线数据通讯情况 + var isSignal = StaticData.PlcDic[0].Read(LineSignal.plcpointAddress); + + if (rfid != null && isSignal != null) + { + //正常读到输送线信息 有到位信号,并且有托盘,获取条码信息 + if (Convert.ToInt32(isSignal) == 1) + { + //获取条码信息 + BaseEquip baseEquip = StaticData.BaseEquip.First(t => t.objid == 2); + var wcsTask = dbContext.WcsTask.Where(t => t.nextPointId == 2).OrderBy(t => t.createTime).FirstOrDefault(); + if (wcsTask != null) + { + if (wcsTask.taskStatus == 5 && (wcsTask.nextPointId == 6 || wcsTask.nextPointId == 2))//入托盘入口,提升机任务是完成状态 + { + object? agvPutValue = null; + object? PalletInIsHas2F = null; + object? ConnectStatus2F = null; + try + { + ConnectStatus2F = StaticData.PlcDic[2].Read(ConnectStatus2FPoint.plcpointAddress);//2F托盘库产线数据通讯情况 + agvPutValue = StaticData.PlcDic[2].Read(agvPutPoint.plcpointAddress); + PalletInIsHas2F = StaticData.PlcDic[2].Read(PalletInIsHas2FPoint.plcpointAddress);//2F托盘库入口上料光电 + } + catch + { + + } + if (wcsTask.taskType != 99)//不是人工任务 + { + bool hasTask = dbContext.WcsTask.Where(t => t.endPointId == inEquip.objid && t.objid != wcsTask.objid).Any(); + if (agvPutValue != null && Convert.ToInt32(agvPutValue) == 1 && !hasTask && Convert.ToInt32(PalletInIsHas2F) == 0 && Convert.ToInt32(ConnectStatus2F) == 1)//小包入口要料 + { + dbContext.Remove(wcsTask);//删除原本的任务 + WcsTask newTask = CoreMapper.Map(wcsTask); + newTask.taskStatus = 0; + newTask.objid = StaticData.SnowId.NextId(); + newTask.nextPointId = agvEquip.objid;//小车执行该任务 + newTask.nextPointNo = agvEquip.equipNo; + newTask.createTime = DateTime.Now; + newTask.updateTime = DateTime.Now; + newTask.containerNo = rfid;//容器号 + newTask.currPointId = lineEquip.objid;//起始地为二楼接驳位 + newTask.currPointNo = lineEquip.equipNo; + newTask.endPointId = inEquip.objid;//终点为小包入口 + newTask.endPointNo = inEquip.equipNo; + newTask.taskType = StaticTaskType.SecondLineToSmallPackage;//提升机到小包入口的任务类型 + newTask.useFlag = 1; + dbContext.Add(newTask); + WcsTaskLog wcsTaskLog = CoreMapper.Map(newTask); + dbContext.Add(wcsTaskLog); + dbContext.SaveChanges(); + _logger.Info("二楼接驳位生成任务入库成功,托盘号:" + rfid); + Console.WriteLine(DateTime.Now + ":二楼接驳位生成任务入库成功,托盘号:" + rfid); + } + else + { + BaseEquip? endEquip = dbContext.BaseEquip.FirstOrDefault(t => t.equipType == 20 && t.useFlag == 1 && t.equipStatus == 0 && t.emptyCount == 0);//二楼周转位 + if (endEquip != null) + { + dbContext.Remove(wcsTask);//删除原本的任务 + WcsTask newTask = CoreMapper.Map(wcsTask); + newTask.taskStatus = 0; + newTask.objid = StaticData.SnowId.NextId(); + newTask.nextPointId = agvEquip.objid;//小车执行该任务 + newTask.nextPointNo = agvEquip.equipNo; + newTask.createTime = DateTime.Now; + newTask.updateTime = DateTime.Now; + newTask.containerNo = rfid;//容器号 + newTask.currPointId = lineEquip.objid;//起始地为二楼接驳位 + newTask.currPointNo = lineEquip.equipNo; + newTask.endPointId = endEquip.objid;//终点为周转位 + newTask.endPointNo = endEquip.equipNo; + newTask.taskType = StaticTaskType.SecondLiftToTransit;//提升机到周转位的任务类型 + newTask.useFlag = 1; + dbContext.Add(newTask); + WcsTaskLog wcsTaskLog = CoreMapper.Map(newTask); + dbContext.Add(wcsTaskLog); + dbContext.SaveChanges(); + _logger.Info("二楼接驳位生成任务入库成功,托盘号:" + rfid); + Console.WriteLine(DateTime.Now + ":二楼接驳位生成任务入库成功,托盘号:" + rfid); + } + } + } + else + { + if (wcsTask.endPointId == 36)//目的地是小包入口 + { + bool hasTask = dbContext.WcsTask.Where(t => t.endPointId == inEquip.objid && t.objid!=wcsTask.objid).Any(); + + if (agvPutValue != null && Convert.ToInt32(agvPutValue) == 1 && !hasTask && Convert.ToInt32(PalletInIsHas2F) == 0 && Convert.ToInt32(ConnectStatus2F) == 1)//小包入口要料 + + { + dbContext.Remove(wcsTask); + WcsTask newTask = CoreMapper.Map(wcsTask); + newTask.taskStatus = 0; + newTask.objid = StaticData.SnowId.NextId(); + newTask.nextPointId = agvEquip.objid; + newTask.nextPointNo = agvEquip.equipNo; + newTask.createTime = DateTime.Now; + newTask.updateTime = DateTime.Now; + newTask.containerNo = rfid; + newTask.currPointId = lineEquip.objid; + newTask.currPointNo = lineEquip.equipNo; + newTask.endPointId = inEquip.objid; + newTask.endPointNo = inEquip.equipNo; + newTask.taskType = StaticTaskType.SecondLineToSmallPackage;//到小包入口 + newTask.useFlag = 1; + dbContext.Add(newTask); + WcsTaskLog wcsTaskLog = CoreMapper.Map(newTask); + dbContext.Add(wcsTaskLog); + dbContext.SaveChanges(); + _logger.Info("二楼接驳位生成任务入库成功,托盘号:" + rfid); + Console.WriteLine(DateTime.Now + ":二楼接驳位生成任务入库成功,托盘号:" + rfid); + } + else + { + BaseEquip? endEquip = dbContext.BaseEquip.FirstOrDefault(t => t.equipType == 20 && t.useFlag == 1 && t.equipStatus == 0 && t.emptyCount == 0); + if (endEquip != null) + { + dbContext.Remove(wcsTask); + WcsTask newTask = CoreMapper.Map(wcsTask); + newTask.taskStatus = 0; + newTask.objid = StaticData.SnowId.NextId(); + newTask.nextPointId = agvEquip.objid; + newTask.nextPointNo = agvEquip.equipNo; + newTask.createTime = DateTime.Now; + newTask.updateTime = DateTime.Now; + newTask.containerNo = rfid; + newTask.currPointId = lineEquip.objid; + newTask.currPointNo = lineEquip.equipNo; + newTask.endPointId = endEquip.objid; + newTask.endPointNo = endEquip.equipNo; + newTask.taskType = StaticTaskType.SecondLiftToTransit;//到周转位 + newTask.useFlag = 1; + newTask.qty = 10; + dbContext.Add(newTask); + WcsTaskLog wcsTaskLog = CoreMapper.Map(newTask); + dbContext.Add(wcsTaskLog); + dbContext.SaveChanges(); + _logger.Info("二楼接驳位生成任务入库成功,托盘号:" + rfid); + Console.WriteLine(DateTime.Now + ":二楼接驳位生成任务入库成功,托盘号:" + rfid); + } + } + } + else if (wcsTask.endPointId == 38)//目的地是废料区 + { + var endEquip = dbContext.BaseEquip.First(t => t.objid == 38);//废料区 + if (endEquip.emptyCount == 0)//废料区没有托盘 + { + dbContext.Remove(wcsTask); + WcsTask newTask = CoreMapper.Map(wcsTask); + newTask.taskStatus = 0; + newTask.objid = StaticData.SnowId.NextId(); + newTask.nextPointId = agvEquip.objid; + newTask.nextPointNo = agvEquip.equipNo; + newTask.createTime = DateTime.Now; + newTask.updateTime = DateTime.Now; + newTask.containerNo = rfid; + newTask.currPointId = lineEquip.objid; + newTask.currPointNo = lineEquip.equipNo; + newTask.taskType = StaticTaskType.SecondLiftToWaste; + newTask.useFlag = 1; + dbContext.Add(newTask); + WcsTaskLog wcsTaskLog = CoreMapper.Map(newTask); + dbContext.Add(wcsTaskLog); + dbContext.SaveChanges(); + _logger.Info("二楼接驳位生成任务入库成功,托盘号:" + rfid); + Console.WriteLine(DateTime.Now + ":二楼接驳位生成任务入库成功,托盘号:" + rfid); + } + else // 废料区有托盘找周转区 + { + endEquip = dbContext.BaseEquip.FirstOrDefault(t => t.equipType == 20 && t.useFlag == 1 && t.equipStatus == 0 && t.emptyCount == 0);//周转位 + if (endEquip != null) + { + dbContext.Remove(wcsTask); + WcsTask newTask = CoreMapper.Map(wcsTask); + newTask.taskStatus = 0; + newTask.objid = StaticData.SnowId.NextId(); + newTask.nextPointId = agvEquip.objid; + newTask.nextPointNo = agvEquip.equipNo; + newTask.createTime = DateTime.Now; + newTask.updateTime = DateTime.Now; + newTask.containerNo = rfid; + newTask.currPointId = lineEquip.objid; + newTask.currPointNo = lineEquip.equipNo; + newTask.endPointId = endEquip.objid; + newTask.endPointNo = endEquip.equipNo; + newTask.taskType = StaticTaskType.SecondLiftToTransit; + newTask.useFlag = 1; + newTask.qty = 1; + dbContext.Add(newTask); + WcsTaskLog wcsTaskLog = CoreMapper.Map(newTask); + dbContext.Add(wcsTaskLog); + dbContext.SaveChanges(); + _logger.Info("二楼接驳位生成任务入库成功,托盘号:" + rfid); + Console.WriteLine(DateTime.Now + ":二楼接驳位生成任务入库成功,托盘号:" + rfid); + } + } + } + } + } + + else if (wcsTask.taskStatus == 8)//小车任务完成 + { + if (wcsTask.taskType == StaticTaskType.SecondStorageToLift && wcsTask.containerNo == rfid)//50是成品出库 + { + BaseEquip endEquip = StaticData.BaseEquip.First(t => t.objid == 1); + dbContext.Remove(wcsTask); + WcsTask newTask = CoreMapper.Map(wcsTask); + newTask.serialNo = SystemData.GetSerialNo(dbContext); + newTask.taskStatus = 0; + newTask.objid = StaticData.SnowId.NextId(); + newTask.nextPointId = tsjEquip.objid; + newTask.nextPointNo = tsjEquip.equipNo; + newTask.createTime = DateTime.Now; + newTask.updateTime = DateTime.Now; + newTask.endPointId = endEquip.objid; + newTask.ud1 = 30; + newTask.endPointNo = endEquip.equipNo; + newTask.containerNo = rfid; + newTask.currPointId = lineEquip.objid; + newTask.currPointNo = lineEquip.equipNo; + newTask.useFlag = 1; + newTask.fromFloorNo = 2; + newTask.floorNo = endEquip.floorNo; + dbContext.Add(newTask); + WcsTaskLog wcsTaskLog = CoreMapper.Map(newTask); + dbContext.Add(wcsTaskLog); + dbContext.SaveChanges(); + _logger.Info("二楼接驳位生成任务出库成功,托盘号:" + rfid); + Console.WriteLine(DateTime.Now + ":二楼接驳位生成任务出库成功,托盘号:" + rfid); + } + else//一般情况下是废料的任务 + { + BaseEquip endEquip = StaticData.BaseEquip.First(t => t.objid == wcsTask.endPointId); + dbContext.Remove(wcsTask); + WcsTask newTask = CoreMapper.Map(wcsTask); + newTask.serialNo = SystemData.GetSerialNo(dbContext); + newTask.taskStatus = 0; + newTask.objid = StaticData.SnowId.NextId(); + newTask.nextPointId = tsjEquip.objid; + newTask.nextPointNo = tsjEquip.equipNo; + newTask.createTime = DateTime.Now; + newTask.updateTime = DateTime.Now; + newTask.ud1 = 30; + newTask.endPointId = endEquip.objid; + newTask.endPointNo = endEquip.equipNo; + newTask.containerNo = rfid; + newTask.currPointId = lineEquip.objid; + newTask.currPointNo = lineEquip.equipNo; + newTask.useFlag = 1; + newTask.fromFloorNo = 2; + newTask.floorNo = endEquip.floorNo; + dbContext.Add(newTask); + WcsTaskLog wcsTaskLog = CoreMapper.Map(newTask); + dbContext.Add(wcsTaskLog); + dbContext.SaveChanges(); + _logger.Info("二楼接驳位生成任务出库成功,托盘号:" + rfid); + Console.WriteLine(DateTime.Now + ":二楼接驳位生成任务出库成功,托盘号:" + rfid); + } + + + } + } + } + } + } + catch (Exception ex) + { + if (ex is PlcException) + { + + } + else + { + _logger.Error(ex.Message + "\n" + ex.StackTrace); + } + } + finally + { + Thread.Sleep(1000); + } + } + } + } +} diff --git a/src/Khd.Core.Wcs/Wcs/SystemTimer.cs b/src/Khd.Core.Wcs/Wcs/SystemTimer.cs new file mode 100644 index 0000000..0289a75 --- /dev/null +++ b/src/Khd.Core.Wcs/Wcs/SystemTimer.cs @@ -0,0 +1,1430 @@ +using AngleSharp.Common; +using Khd.Core.Domain.Dto; +using Khd.Core.Domain.Dto.waring; +using Khd.Core.Domain.Dto.webapi; +using Khd.Core.Domain.Models; +using Khd.Core.EntityFramework; +using Khd.Core.Library; +using Khd.Core.Library.Mapper; +using Khd.Core.Plc.S7; +using Khd.Core.Wcs.Global; +using Masuit.Tools; +using Microsoft.EntityFrameworkCore; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; +using Newtonsoft.Json; +using System.Diagnostics; +using Z.EntityFramework.Plus; + +namespace Khd.Core.Wcs.Wcs +{ + public class SystemTimer + { + private readonly LoggerUtils _logger = new(); + private readonly IHost host; + + public SystemTimer(IHost host) + { + this.host = host; + } + + public void Start() + { + var messageSynchronousThread = new Thread(MessageSynchronousLogic) + { + Name = "MessageSynchronousThread", + IsBackground = true + }; + messageSynchronousThread.Start();//陈工设备信息推送 + + var PlcHeartBeat30Thread = new Thread(PlcHeartBeat30Logic) + { + Name = "PlcHeartBeat30Thread", + IsBackground = true + }; + PlcHeartBeat30Thread.Start();//脉冲 + + var PlcHeartBeat31Thread = new Thread(PlcHeartBeat31Logic) + { + Name = "PlcHeartBeat31Thread", + IsBackground = true + }; + PlcHeartBeat31Thread.Start();//脉冲 + + var PlcHearBeat220Thread = new Thread(PlcHearBeat220Logic) + { + Name = "PlcHeartBeat220Thread", + IsBackground = true + }; + PlcHearBeat220Thread.Start(); + + var deleteTaskThread = new Thread(DeleteTaskLogic) + { + Name = "DeleteTaskThread", + IsBackground = true + }; + deleteTaskThread.Start(); + + var deleteLogsThread = new Thread(DeleteLogsLogic) + { + Name = "DeleteLogsThread", + IsBackground = true + }; + deleteLogsThread.Start(); + + //var AgvAlarmThread = new Thread(AgvAlarmLogic) + //{ + // Name = "AgvAlarmThread", + // IsBackground = true + //}; + //AgvAlarmThread.Start(); + + var trayReadThread = new Thread(TrayReadLogic) + { + Name = "TrayReadThread", + IsBackground = true + }; + trayReadThread.Start(); + + var locationThread = new Thread(LocationLogic) + { + Name = "LocationThread", + IsBackground = true + }; + locationThread.Start(); + + Console.WriteLine($"{DateTime.Now}: SystemTimer started"); + } + + private void TrayReadLogic(object? obj) + { + Dictionary readCount = new Dictionary() + { + {1,0 }, + {2,0 }, + {3,0 }, + {4,0 }, + {5,0 }, + }; + while (true) + { + try + { + foreach (var item in readCount) + { + BasePlcpoint signal = StaticData.BasePlcpointList.First(t => t.plcpointNo == $"linesignal0{item.Key}"); + BasePlcpoint rfid = StaticData.BasePlcpointList.First(t => t.plcpointNo == $"RFID00{item.Key}"); + BasePlcpoint read = StaticData.BasePlcpointList.First(t => t.plcpointNo == $"Read0{item.Key}"); + var signalValue = StaticData.PlcDic[0].Read(signal.plcpointAddress); + var rfidValue = StaticData.PlcDic[0].ReadRFID(rfid.plcpointAddress); + var readValue = StaticData.PlcDic[0].Read(read.plcpointAddress); + if (Convert.ToInt32(signalValue) == 1 && string.IsNullOrEmpty(rfidValue) && item.Value < 10) + { + StaticData.PlcDic[0].WriteToPoint(read.plcpointAddress, true, read.plcpointLength.ToString()); + readCount[item.Key] = +1; + Task.Run(() => + { + Thread.Sleep(2000); + StaticData.PlcDic[0].WriteToPoint(read.plcpointAddress, false, read.plcpointLength.ToString()); + }); + } + if (Convert.ToInt32(signalValue) == 1 && !string.IsNullOrEmpty(rfidValue) || Convert.ToInt32(signalValue) == 0) + { + readCount[item.Key] = 0; + if (Convert.ToBoolean(readValue)) + { + StaticData.PlcDic[0].WriteToPoint(read.plcpointAddress, false, read.plcpointLength.ToString()); + } + } + } + } + catch + { + + } + Thread.Sleep(3000); + } + } + + private void LocationLogic() + { + using var scope = host.Services.CreateScope(); + using var dbContext = scope.ServiceProvider.GetRequiredService(); + List basePlcs = dbContext.BasePlc.Where(t => t.Station.Contains("库位")).ToList(); + StaticData.LocationToPlcList = basePlcs.Select(t => new + { + t.Id, + Station = t.Station.Replace("库位", ""), + t.Address, + locRow = t.Name.Substring(t.Name.IndexOf('[') + 1, 1), + locColumn = t.Name.Substring(t.Name.IndexOf(',') + 1).Replace("]", "").Replace("五楼半成品[", ""), + }).Select(t => new LocationPlcDto + { + Id = t.Id, + Station = t.Station, + Address = t.Address, + locRow = t.locRow, + locColumn = t.locColumn.Substring(0, t.locColumn.IndexOf(',') == -1 ? t.locColumn.Length : t.locColumn.IndexOf(',')), + layerNum = t.locColumn.IndexOf(',') == -1 ? "1" : t.locColumn.Substring(t.locColumn.IndexOf(',') == -1 ? 0 : t.locColumn.IndexOf(',') + 1) + }); + + while (true) + { + try + { + var locations = dbContext.WmsBaseLocation.OrderBy(t => t.locRow).OrderBy(t => t.locColumn).ToList(); + foreach (var item in StaticData.LocationToPlcList) + { + WmsBaseLocation? wmsBaseLocation = locations.Where(t => t.locRow.ToString() == item.locRow) + .Where(t => t.locColumn.ToString() == item.locColumn) + .Where(t => t.layerNum.ToString() == item.layerNum) + .Where(t => t.warehouseId.ToString() == item.Station) + .FirstOrDefault(); + if (wmsBaseLocation != null && !string.IsNullOrEmpty(wmsBaseLocation.containerCode)) + { + if (wmsBaseLocation.warehouseId == 512) + { + if (wmsBaseLocation.ContainerStatus == "1") + { + StaticData.PlcDic[2].Write(item.Address, true); + } + else + { + StaticData.PlcDic[2].Write(item.Address, false); + } + } + else + { + StaticData.PlcDic[2].Write(item.Address, true); + } + } + else + { + StaticData.PlcDic[2].Write(item.Address, false); + } + } + } + catch + { + + } + Thread.Sleep(1000 * 60 * 5); + } + } + + private void AgvAlarmLogic() + { + using var scope = host.Services.CreateScope(); + using var dbContext = scope.ServiceProvider.GetRequiredService(); + while (true) + { + using var transaction = dbContext.Database.BeginTransaction(); + try + { + dbContext.ChangeTracker.Clear(); + var dmsBaseDeviceLedgers = dbContext.DmsBaseDeviceLedger.ToList(); + var wcsAgvStatuses = dbContext.WcsAgvStatus.ToList(); + var agvStatus = from a in dmsBaseDeviceLedgers + from b in wcsAgvStatuses + where a.DeviceCode == b.RobotCode + select new + { + a.DeviceId, + b.Online, + b.Status + }; + foreach (var item in agvStatus) + { + //var dmsBaseAlarmRule = StaticData.DmsBaseAlarmRuleList.Where(t => t.Status == item.Status).FirstOrDefault(); + var dmsBaseAlarmRule = StaticData.DmsBaseAlarmRuleList.FirstOrDefault(); + if (dmsBaseAlarmRule != null) + { + DmsRecordAlarmTime alarmTime = new DmsRecordAlarmTime + { + AlarmBeginTime = DateTime.Now, + AlarmReason = dmsBaseAlarmRule.AlarmReason, + HandleSuggest = dmsBaseAlarmRule.HandleSuggest, + AlarmRuleId = dmsBaseAlarmRule.AlarmRuleId, + ContinueTime = dmsBaseAlarmRule.ContinueTime, + CreateBy = "WCS", + CreateTime = DateTime.Now, + DeviceId = item.DeviceId, + }; + var dmsRecordAlarmInfo = CoreMapper.Map(alarmTime); + dmsRecordAlarmInfo.AlarmStatus = "0"; + dmsRecordAlarmInfo.NoticeStatus = "0"; + dbContext.Add(dmsRecordAlarmInfo); + dbContext.SaveChanges(); + transaction.Commit(); + } + else + { + var alarmTime = dbContext.DmsRecordAlarmTime + .Where(t => t.CreateBy == "WCS") + .Where(t => t.DeviceId == item.DeviceId) + .FirstOrDefault(); + if (alarmTime != null) + { + dbContext.Remove(alarmTime); + dbContext.DmsRecordAlarmInfo + .Where(t => t.AlarmId == alarmTime.AlarmId) + .Update(t => new DmsRecordAlarmInfo + { + AlarmEndTime = DateTime.Now, + UpdateBy = "WCS", + UpdateTime = DateTime.Now + }); + dbContext.SaveChanges(); + transaction.Commit(); + } + } + } + } + catch + { + try + { + transaction.Rollback(); + } + catch + { + + } + } + Thread.Sleep(3000); + } + } + + /// + /// 定时清除日志文件 + /// + private void DeleteLogsLogic() + { + while (true) + { + try + { + //获取当前程序运行目录下的logs文件夹 + string logPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "logs"); + string[] strings = Directory.GetDirectories(logPath); + foreach (string s in strings) + { + string? dirName = Path.GetFileName(s); + if (dirName != null) + { + if (DateTime.TryParse(dirName, out DateTime dt)) + { + if (dt < DateTime.Now.AddDays(-StaticData.DeleteLogDay)) + { + Directory.Delete(s, true); + _logger.Info($"日志{dirName}已删除"); + } + } + } + } + + } + catch + { + + } + Thread.Sleep(1000 * 60 * 60 * 23); + } + } + + /// + /// 删除任务 + /// + private void DeleteTaskLogic() + { + using var scope = host.Services.CreateScope(); + using var dbContext = scope.ServiceProvider.GetRequiredService(); + while (true) + { + try + { + dbContext.ChangeTracker.Clear(); + + #region 人工任务完成自动删除 + WcsTask? wcsTask = dbContext.WcsTask.FirstOrDefault(t => t.taskType == 99 && t.taskStatus == 5); + if (wcsTask!=null && wcsTask.endPointId<=5) + { //人工任务已经完成,自动删除 + dbContext.Remove(wcsTask); + dbContext.SaveChanges(); + } + #endregion + + List wcsTasks = dbContext.WcsTask.Where(t => t.IsDelete == 1).ToList(); + foreach (var item in wcsTasks) + { + BaseEquip agvEquip = StaticData.BaseEquip.First(t => t.objid == item.nextPointId); + if (!string.IsNullOrEmpty(item.taskCode) && !string.IsNullOrEmpty(agvEquip.serverIp)) + { + if (item.endPointId == 11) + { + dbContext.Remove(item); + if (item.taskStatus == 6) + { + dbContext.SaveChanges(); + } + else + { + var cancelTask = new + { + reqCode = StaticData.SnowId.NextId().ToString(), + taskCode = item.taskCode + }; + string reponse = HttpHelper.SendPostMessage(agvEquip.serverIp, agvEquip.serverPort.Value, "rcms/services/rest/hikRpcService/cancelTask", cancelTask.ToJsonString()); + var result = JsonConvert.DeserializeObject(reponse); + if (result != null && result.code == "0") + { + dbContext.SaveChanges(); + _logger.Info($"任务{item.taskCode}已删除"); + } + else + { + _logger.Error($"任务{item.taskCode}删除失败,原因:{result?.message}"); + } + } + } + else + { + dbContext.Remove(item); + var cancelTask = new + { + reqCode = StaticData.SnowId.NextId().ToString(), + taskCode = item.taskCode + }; + string reponse = HttpHelper.SendPostMessage(agvEquip.serverIp, agvEquip.serverPort.Value, "rcms/services/rest/hikRpcService/cancelTask", cancelTask.ToJsonString()); + var result = JsonConvert.DeserializeObject(reponse); + if (result != null && result.code == "0") + { + dbContext.SaveChanges(); + _logger.Info($"任务{item.taskCode}已删除"); + } + else + { + _logger.Error($"任务{item.taskCode}删除失败,原因:{result?.message}"); + } + } + WmsBaseLocation? wmsBaseLocation = dbContext.WmsBaseLocation.FirstOrDefault(t => t.locationCode == item.currPointNo); + WmsBaseLocation? toBaseLocation = dbContext.WmsBaseLocation.FirstOrDefault(t => t.locationCode == item.endPointNo); + if (wmsBaseLocation != null) + { + SystemData.UnLockOutLocation(wmsBaseLocation, dbContext); + } + if (toBaseLocation != null) + { + SystemData.UnLockOutLocation(toBaseLocation, dbContext); + } + dbContext.SaveChanges(); + } + else + { + dbContext.Remove(item); + dbContext.SaveChanges(); + _logger.Info($"任务{item.objid}已删除"); + } + } + } + catch + { + + } + Thread.Sleep(1000); + } + } + + + /// + /// 定时发送心跳包 + /// + private void PlcHearBeat220Logic() + { + using var scope = host.Services.CreateScope(); + using var dbContext = scope.ServiceProvider.GetRequiredService(); + BasePlcpoint HeartBeat30 = StaticData.BasePlcpointList.First(t => t.plcpointNo == "putTray"); + int errorCount = 0; + bool isOver = false; + while (true) + { + try + { + if (errorCount > 3) + { + _logger.Error($"Plc220短线重连失败超过{errorCount}次"); + dbContext.ChangeTracker.Clear(); + SystemData.InsertWaringLog(dbContext, WaringType.设备Plc通讯异常, $"Plc220短线重连失败超过{errorCount}次"); + //var dmsRecordAlarmTime = dbContext.DmsRecordAlarmTime.Where(t => t.CreateBy == "WCS" && t.DeviceId == 15).FirstOrDefault(); + //if (dmsRecordAlarmTime == null) + //{ + // var alarmTime = new DmsRecordAlarmTime + // { + // DeviceId = 15, + // AlarmBeginTime = DateTime.Now, + // AlarmReason = "Plc220短线重连失败", + // HandleSuggest = "检查Plc220网络连接", + // AlarmRuleId = 4, + // ContinueTime = 10000, + // CreateBy = "WCS", + // CreateTime = DateTime.Now, + // }; + // var dmsRecordAlarmInfo = CoreMapper.Map(alarmTime); + // dmsRecordAlarmInfo.AlarmStatus = "0"; + // dmsRecordAlarmInfo.NoticeStatus = "0"; + // dbContext.Add(dmsRecordAlarmInfo); + // dbContext.SaveChanges(); + //} + } + StaticData.PlcDic[2].Read(HeartBeat30.plcpointAddress); + dbContext.ChangeTracker.Clear(); + SystemData.DeleteWaringLog(dbContext, WaringType.设备Plc通讯异常); + + } + catch + { + try + { + StaticData.PlcDic[2] = new Plc.S7.Plc(StaticData.PlcDic[2].CPU, StaticData.PlcDic[2].IP, StaticData.PlcDic[2].Port, StaticData.PlcDic[2].Rack, StaticData.PlcDic[2].Slot); + StaticData.PlcDic[2].Open(); + isOver = true; + } + catch (Exception ex2) + { + errorCount++; + isOver = false; + _logger.Error("Plc短线重连失败" + ex2.Message); + } + } + Thread.Sleep(1000); + } + } + + /// + /// 定时发送心跳包 + /// + private void PlcHeartBeat30Logic() + { + using var scope = host.Services.CreateScope(); + using var dbContext = scope.ServiceProvider.GetRequiredService(); + BasePlcpoint HeartBeat30 = StaticData.BasePlcpointList.First(t => t.plcpointNo == "HeartBeat30"); + bool heartBeatCount = false; + bool isOver = false; + int errorCount = 0; + while (true) + { + try + { + if (errorCount > 3) + { + _logger.Error($"Plc30短线重连失败超过{errorCount}次"); + dbContext.ChangeTracker.Clear(); + SystemData.InsertWaringLog(dbContext, WaringType.提升机Plc通讯异常, $"Plc30短线重连失败超过{errorCount}次"); + //var dmsRecordAlarmTime = dbContext.DmsRecordAlarmTime.Where(t => t.CreateBy == "WCS" && t.DeviceId == 13).FirstOrDefault(); + //if (dmsRecordAlarmTime == null) + //{ + // var alarmTime = new DmsRecordAlarmTime + // { + // DeviceId = 13, + // AlarmBeginTime = DateTime.Now, + // AlarmReason = "Plc30短线重连失败", + // HandleSuggest = "检查Plc30网络连接", + // AlarmRuleId = 4, + // ContinueTime = 10000, + // CreateBy = "WCS", + // CreateTime = DateTime.Now, + // }; + // var dmsRecordAlarmInfo = CoreMapper.Map(alarmTime); + // dmsRecordAlarmInfo.AlarmStatus = "0"; + // dmsRecordAlarmInfo.NoticeStatus = "0"; + // dbContext.Add(dmsRecordAlarmTime); + // dbContext.Add(dmsRecordAlarmInfo); + // dbContext.SaveChanges(); + //} + } + heartBeatCount = !heartBeatCount; + StaticData.PlcDic[0].WriteToPoint(HeartBeat30.plcpointAddress, heartBeatCount, HeartBeat30.plcpointLength?.ToString()); + dbContext.ChangeTracker.Clear(); + SystemData.DeleteWaringLog(dbContext, WaringType.提升机Plc通讯异常); + } + catch + { + try + { + StaticData.PlcDic[0] = new Plc.S7.Plc(StaticData.PlcDic[0].CPU, StaticData.PlcDic[0].IP, StaticData.PlcDic[0].Port, StaticData.PlcDic[0].Rack, StaticData.PlcDic[0].Slot); + StaticData.PlcDic[0].Open(); + isOver = true; + } + catch (Exception ex2) + { + errorCount++; + isOver = false; + _logger.Error("Plc短线重连失败" + ex2.Message); + } + } + Thread.Sleep(1000); + } + } + + /// + /// 定时发送心跳包 + /// + private void PlcHeartBeat31Logic() + { + using var scope = host.Services.CreateScope(); + using var dbContext = scope.ServiceProvider.GetRequiredService(); + BasePlcpoint HeartBeat31 = StaticData.BasePlcpointList.First(t => t.plcpointNo == "CTUHeart"); + bool heartBeatCount = false; + bool isOver = false; + int errorCount = 0; + while (true) + { + try + { + if (errorCount > 3) + { + _logger.Error($"Plc31短线重连失败超过{errorCount}次"); + dbContext.ChangeTracker.Clear(); + + SystemData.InsertWaringLog(dbContext, WaringType.U型线Plc通讯异常, $"Plc31短线重连失败超过{errorCount}次"); + //var dmsRecordAlarmTime = dbContext.DmsRecordAlarmTime.Where(t => t.CreateBy == "WCS" && t.DeviceId == 14).FirstOrDefault(); + //if (dmsRecordAlarmTime == null) + //{ + // var alarmTime = new DmsRecordAlarmTime + // { + // DeviceId = 14, + // AlarmBeginTime = DateTime.Now, + // AlarmReason = "Plc31短线重连失败", + // HandleSuggest = "检查Plc31网络连接", + // AlarmRuleId = 4, + // ContinueTime = 10000, + // CreateBy = "WCS", + // CreateTime = DateTime.Now, + // }; + // var dmsRecordAlarmInfo = CoreMapper.Map(alarmTime); + // dmsRecordAlarmInfo.AlarmStatus = "0"; + // dmsRecordAlarmInfo.NoticeStatus = "0"; + // dbContext.Add(dmsRecordAlarmInfo); + // dbContext.SaveChanges(); + //} + } + heartBeatCount = !heartBeatCount; + StaticData.PlcDic[1].WriteToPoint(HeartBeat31.plcpointAddress, heartBeatCount, HeartBeat31.plcpointLength?.ToString()); + dbContext.ChangeTracker.Clear(); + SystemData.DeleteWaringLog(dbContext, WaringType.U型线Plc通讯异常); + } + catch (Exception ex) + { + if (ex is PlcException) + { + try + { + StaticData.PlcDic[1] = new Plc.S7.Plc(StaticData.PlcDic[1].CPU, StaticData.PlcDic[1].IP, StaticData.PlcDic[1].Port, StaticData.PlcDic[1].Rack, StaticData.PlcDic[1].Slot); + StaticData.PlcDic[1].Open(); + isOver = true; + } + catch (Exception ex2) + { + errorCount++; + isOver = false; + _logger.Error("Plc短线重连失败" + ex2.Message); + } + } + else + { + _logger.Error(ex.Message + "\n" + ex.StackTrace); + } + } + Thread.Sleep(1000); + } + } + + /// + /// 定时更新基础设备信息 + /// + private void BaseEquipLogic() + { + using var scope = host.Services.CreateScope(); + using var dbContext = scope.ServiceProvider.GetRequiredService(); + while (true) + { + try + { + dbContext.ChangeTracker.Clear(); + List updateEquips = dbContext.BaseEquip.Where(t => t.remark == "99").ToList(); + if (updateEquips.Count > 0) + { + foreach (var equip in updateEquips) + { + equip.remark = "0"; + dbContext.Update(equip); + dbContext.SaveChanges(); + } + StaticData.BaseEquip = dbContext.BaseEquip.ToList(); + } + } + catch + { + + } + Thread.Sleep(5000); + } + } + + /// + /// 定时同步消息 + /// + private void MessageSynchronousLogic() + { + while (true) + { + FiveAgvStatusLogic(); + SecondAgvLogic(); + ThirdAgvLogic(); + SendTrayMessage(); + HositerLogic(); + CtuLineLogic(); + FiveAgvLogic(); + FiveBearAgvLogic(); + CtuCmdLogic(); + UpdatePlcPointValue(); + BasePlcPointUpdateLogic(); + AgvWaringLogic(); + AgvCXLogic(); + Thread.Sleep(500); + } + } + + private void AgvCXLogic() + { + + try + { + using var scope = host.Services.CreateScope(); + using var dbContext = scope.ServiceProvider.GetRequiredService(); + dbContext.ChangeTracker.Clear(); + var wcsAgvStatuses = dbContext.WcsAgvStatus.ToList(); + foreach (var item in wcsAgvStatuses) + { + var basePlc = StaticData.basePlcs.FirstOrDefault(t => t.Name == (item.AgvName + "朝向")); + if (basePlc != null && int.TryParse(item.RobotDir, out var dir)) + { + int cx = 0; + if (dir >= -180 && dir < -90) + { + cx = 0; + } + else if (dir >= -90 && dir < 0) + { + cx = 1; + } + else if (dir >= 0 && dir < 90) + { + cx = 2; + } + else if (dir >= 90 && dir <= 180) + { + cx = 3; + } + StaticData.PlcDic[2].WriteToPoint(basePlc.Address, cx, basePlc.type); + } + } + } + catch + { + + } + } + + private void AgvWaringLogic() + { + using var scope = host.Services.CreateScope(); + using var dbContext = scope.ServiceProvider.GetRequiredService(); + try + { + // dbContext.Database.BeginTransaction(); + dbContext.ChangeTracker.Clear(); + var dmsBaseAlarmRules = StaticData.DmsBaseAlarmRuleList.Where(t => t.DeviceId == -1).ToList(); + var wcsAgvStatuses = dbContext.WcsAgvStatus.ToList(); + var robotCodes = wcsAgvStatuses.Select(t => long.Parse(t.RobotCode)).ToList(); + var dmsRecordAlarmTimes = dbContext.DmsRecordAlarmTime.Where(t => robotCodes.Contains(t.DeviceId)).ToList(); + foreach (var agvStatus in wcsAgvStatuses) + { + var dmsBaseAlarmRule = dmsBaseAlarmRules.Where(t => t.Status.ToString() == agvStatus.Status).FirstOrDefault(); + var dmsRecordAlarmTime = dmsRecordAlarmTimes + .Where(t => t.DeviceId == int.Parse(agvStatus.RobotCode)).FirstOrDefault(); + if (dmsBaseAlarmRule != null) + { + if (dmsRecordAlarmTime == null) + { + dmsRecordAlarmTime = new DmsRecordAlarmTime + { + DeviceId = int.Parse(agvStatus.RobotCode), + AlarmBeginTime = DateTime.Now, + AlarmReason = dmsBaseAlarmRule.AlarmReason, + HandleSuggest = dmsBaseAlarmRule.HandleSuggest, + AlarmRuleId = dmsBaseAlarmRule.AlarmRuleId, + ContinueTime = dmsBaseAlarmRule.ContinueTime, + CreateBy = "WCS", + CreateTime = DateTime.Now, + }; + var dmsRecordAlarmInfo = CoreMapper.Map(dmsRecordAlarmTime); + dmsRecordAlarmInfo.NoticeStatus = "0"; + dmsRecordAlarmInfo.AlarmStatus = "0"; + dbContext.Add(dmsRecordAlarmInfo); + dbContext.Add(dmsRecordAlarmTime); + dbContext.SaveChanges(); + } + else + { + if (dmsRecordAlarmTime.AlarmReason != dmsBaseAlarmRule.AlarmReason) + { + dbContext.Remove(dmsRecordAlarmTime); + dbContext.DmsRecordAlarmInfo.Where(t => t.AlarmId == dmsRecordAlarmTime.AlarmId) + .Update(t => new DmsRecordAlarmInfo { AlarmStatus = "2", AlarmEndTime = DateTime.Now }); + var newDmsRecordAlarmTime = new DmsRecordAlarmTime + { + DeviceId = int.Parse(agvStatus.RobotCode), + AlarmBeginTime = DateTime.Now, + AlarmReason = dmsBaseAlarmRule.AlarmReason, + HandleSuggest = dmsBaseAlarmRule.HandleSuggest, + AlarmRuleId = dmsBaseAlarmRule.AlarmRuleId, + ContinueTime = dmsBaseAlarmRule.ContinueTime, + CreateBy = "WCS", + CreateTime = DateTime.Now, + }; + var dmsRecordAlarmInfo = CoreMapper.Map(newDmsRecordAlarmTime); + dmsRecordAlarmInfo.NoticeStatus = "0"; + dmsRecordAlarmInfo.AlarmStatus = "0"; + dbContext.Add(dmsRecordAlarmInfo); + dbContext.Add(newDmsRecordAlarmTime); + dbContext.SaveChanges(); + } + } + } + else + { + if (dmsRecordAlarmTime != null) + { + dbContext.Remove(dmsRecordAlarmTime); + dbContext.DmsRecordAlarmInfo.Where(t => t.AlarmId == dmsRecordAlarmTime.AlarmId) + .Update(t => new DmsRecordAlarmInfo { AlarmStatus = "2", AlarmEndTime = DateTime.Now }); + dbContext.SaveChanges(); + } + } + } + // dbContext.Database.CommitTransaction(); + } + catch + { + // dbContext.Database.RollbackTransaction(); + } + } + + /// + /// 五楼AGV状态 + /// + private void FiveAgvStatusLogic() + { + try + { + using var scope = host.Services.CreateScope(); + using var dbContext = scope.ServiceProvider.GetRequiredService(); + var baseEquip = StaticData.BaseEquip.First(t => t.objid == 10); + var data = new + { + reqCode = StaticData.SnowId.NextId(), + mapCode = "EE" + }; + string result = HttpHelper.SendPostMessage(baseEquip.serverIp, baseEquip.serverPort.Value, "rcms-dps/rest/queryAgvStatus", data.ToJsonString()); + var reponse = JsonConvert.DeserializeObject(result); + if (reponse != null && reponse.code == "0") + { + var AgvCardStatus = reponse.data.First(t => t.RobotCode == "2034"); + AgvCardStatus.DateNow = DateTime.Now; + AgvCardStatus.AgvName = "5楼叉车"; + dbContext.Update(AgvCardStatus); + var BearCardStatus = reponse.data.First(t => t.RobotCode == "6011"); + BearCardStatus.AgvName = "5楼背负式"; + BearCardStatus.DateNow = DateTime.Now; + dbContext.Update(BearCardStatus); + var CtuCardStatus = reponse.data.First(t => t.RobotCode == "8161"); + CtuCardStatus.AgvName = "5楼CTU"; + CtuCardStatus.DateNow = DateTime.Now; + dbContext.Update(CtuCardStatus); + dbContext.SaveChanges(); + } + } + catch + { + + } + } + + /// + /// 获取Plc的值 及报警信息同步 + /// + private void BasePlcPointUpdateLogic() + { + try + { + Stopwatch stopwatch = new Stopwatch(); + stopwatch.Start(); // 开始计时 + + using var scope = host.Services.CreateScope(); + using var dbContext = scope.ServiceProvider.GetRequiredService(); + List plcs = StaticData.PlcDic.Values.ToList(); + + foreach (var item in StaticData.BasePlcpointList.Where(t => !string.IsNullOrEmpty(t.plcpointAddress))) + { + if (!string.IsNullOrEmpty(item.plcpointAddress)) + { + try + { + if (item.plcpointNo.Contains("RFID")) + item.definefield1 = plcs.Where(t => t.IP == item.definefield3).First().ReadRFID(item.plcpointAddress)?.ToString(); + else + { + item.definefield1 = plcs.Where(t => t.IP == item.definefield3).First().Read(item.plcpointAddress)?.ToString(); + + #region 提升机报警点位,需要添加报警记录 + if (item.plcpointNo.Contains("提升机报警采集专用点位")) + { + if(item.definefield1 == "True" || item.definefield1 == "1") + { //添加报警 + SystemData.InsertWaringLog(dbContext, item.plcpointName, item.plcpointName); + } + else + { + //如有报警需消除 + SystemData.DeleteWaringLog(dbContext, item.plcpointName); + } + } + #endregion + } + } + catch + { + + } + } + } + + dbContext.UpdateRange(StaticData.BasePlcpointList.Where(t => !string.IsNullOrEmpty(t.plcpointAddress))); + dbContext.SaveChanges(); + + stopwatch.Stop(); // 停止计时 + // Console.WriteLine($"BasePlcPointUpdateLogic 方法执行时间: {stopwatch.ElapsedMilliseconds} 毫秒"); + } + catch + { + + } + } + + /// + /// 托盘库 + /// + private void SendTrayMessage() + { + try + { + using var scope = host.Services.CreateScope(); + using var dbContext = scope.ServiceProvider.GetRequiredService(); + BaseEquip baseEquip = dbContext.BaseEquip.First(t => t.objid == 40); + BasePlcpoint oneInPoint = StaticData.BasePlcpointList.First(t => t.plcpointNo == "oneIn"); + BasePlcpoint oneOutPoint = StaticData.BasePlcpointList.First(t => t.plcpointNo == "oneOut"); + BasePlcpoint someOutPoint = StaticData.BasePlcpointList.First(t => t.plcpointNo == "someOut"); + BasePlcpoint someInPoint = StaticData.BasePlcpointList.First(t => t.plcpointNo == "someIn"); + BasePlc basePlc = StaticData.basePlcs.First(t => t.Name == "托盘库去向"); + BasePlc basePlc2 = StaticData.basePlcs.First(t => t.Name == "托盘库数量"); + string? value = "0"; + if (StaticData.PlcDic[0].Read(oneInPoint.plcpointAddress)?.ToString() == "1") + { + value = "1"; + } + else if (StaticData.PlcDic[0].Read(oneOutPoint.plcpointAddress)?.ToString() == "1") + { + value = "2"; + } + else if (StaticData.PlcDic[0].Read(someOutPoint.plcpointAddress)?.ToString() == "1") + { + value = "3"; + } + else if (StaticData.PlcDic[0].Read(someInPoint.plcpointAddress)?.ToString() == "1") + { + value = "4"; + } + StaticData.PlcDic[2].WriteToPoint(basePlc.Address, value, basePlc.type); + StaticData.PlcDic[2].WriteToPoint(basePlc2.Address, baseEquip.emptyCount.ToString(), basePlc2.type); + } + catch + { + + } + } + + /// + /// 修改Plc点位信息 + /// + private void UpdatePlcPointValue() + { + try + { + using var scope = host.Services.CreateScope(); + using var dbContext = scope.ServiceProvider.GetRequiredService(); + foreach (var item in StaticData.basePlcs) + { + item.Value = StaticData.PlcDic[2].Read(item.Address)?.ToString(); + } + dbContext.UpdateRange(StaticData.basePlcs); + dbContext.SaveChanges(); + } + catch + { + + } + } + + /// + /// 定时更新三楼AGV信息 + /// + public void ThirdAgvLogic() + { + try + { + using var scope = host.Services.CreateScope(); + using var dbContext = scope.ServiceProvider.GetRequiredService(); + var baseEquip = StaticData.BaseEquip.First(t => t.objid == 9); + dbContext.ChangeTracker.Clear(); + var basePlcs = StaticData.basePlcs.Where(t => t.Station == "3楼AGV").ToList(); + var data = new + { + reqCode = StaticData.SnowId.NextId(), + mapCode = "BB" + }; + string result = HttpHelper.SendPostMessage(baseEquip.serverIp, baseEquip.serverPort.Value, "rcms-dps/rest/queryAgvStatus", data.ToJsonString()); + var reponse = JsonConvert.DeserializeObject(result); + if (reponse != null && reponse.code == "0") + { + var cardStatus = reponse.data.First(t => t.RobotCode == "2032"); + cardStatus.DateNow = DateTime.Now; + cardStatus.AgvName = "3楼叉车 "; + dbContext.Update(cardStatus); + dbContext.SaveChanges(); + var quantityPlc = basePlcs.First(t => t.Name.Contains("电量")); + StaticData.PlcDic[2].WriteToPoint(quantityPlc.Address, cardStatus.Battery, quantityPlc.type); + var XPlc = basePlcs.First(t => t.Name.Contains('X')); + var Ylc = basePlcs.First(t => t.Name.Contains('Y')); + var status = basePlcs.First(t => t.Name.Contains("Status")); if (cardStatus.Online.ToLower() == "true") + { + StaticData.PlcDic[2].WriteToPoint(status.Address, cardStatus.Status, status.type); + } + else + { + StaticData.PlcDic[2].WriteToPoint(status.Address, -1, status.type); + } + StaticData.PlcDic[2].WriteToPoint(XPlc.Address, cardStatus.PosX.ToString(), XPlc.type); + StaticData.PlcDic[2].WriteToPoint(Ylc.Address, cardStatus.PosY.ToString(), Ylc.type); + #region 经过走廊区域报警 + var Agv3FLED = StaticData.BasePlcpointList.First(t => t.id == 76); + if (Agv3FLED != null) + { + if (int.Parse(cardStatus.PosX) >= 53040 && int.Parse(cardStatus.PosX) <= 58090 && (int.Parse(cardStatus.PosY) >= 53520 && int.Parse(cardStatus.PosY) <= 64590)) + { + //Console.WriteLine("=======>3F走廊区域预警"); + + StaticData.PlcDic[0].WriteToPoint(Agv3FLED.plcpointAddress, true, Agv3FLED.plcpointLength.ToString()); + } + else + { + //Console.WriteLine("3F走廊区域正常"); + StaticData.PlcDic[0].WriteToPoint(Agv3FLED.plcpointAddress, false, Agv3FLED.plcpointLength.ToString()); + } + } + #endregion + } + } + catch + { + + } + } + + /// + /// 定时更新二楼AGV信息 + /// + private void SecondAgvLogic() + { + try + { + using var scope = host.Services.CreateScope(); + using var dbContext = scope.ServiceProvider.GetRequiredService(); + dbContext.ChangeTracker.Clear(); + var baseEquip = StaticData.BaseEquip.First(t => t.objid == 8); + var basePlcs = StaticData.basePlcs.Where(t => t.Station == "2楼AGV").ToList(); + var data = new + { + reqCode = StaticData.SnowId.NextId(), + mapCode = "CC" + }; + string result = HttpHelper.SendPostMessage(baseEquip.serverIp, baseEquip.serverPort.Value, "rcms-dps/rest/queryAgvStatus", data.ToJsonString()); + var reponse = JsonConvert.DeserializeObject(result); + if (reponse != null && reponse.code == "0") + { + var cardStatus = reponse.data.First(t => t.RobotCode == "2033"); + cardStatus.DateNow = DateTime.Now; + cardStatus.AgvName = "2楼叉车"; + dbContext.Update(cardStatus); + dbContext.SaveChanges(); + var quantityPlc = basePlcs.First(t => t.Name.Contains("电量")); + StaticData.PlcDic[2].WriteToPoint(quantityPlc.Address, cardStatus.Battery, quantityPlc.type); + var XPlc = basePlcs.First(t => t.Name.Contains('X')); + var Ylc = basePlcs.First(t => t.Name.Contains('Y')); + var status = basePlcs.First(t => t.Name.Contains("Status")); + if (cardStatus.Online.ToLower() == "true") + { + StaticData.PlcDic[2].WriteToPoint(status.Address, cardStatus.Status, status.type); + } + else + { + StaticData.PlcDic[2].WriteToPoint(status.Address, -1, status.type); + } + StaticData.PlcDic[2].WriteToPoint(XPlc.Address, cardStatus.PosX.ToString(), XPlc.type); + StaticData.PlcDic[2].WriteToPoint(Ylc.Address, cardStatus.PosY.ToString(), Ylc.type); + + #region 经过走廊区域报警 + var Agv2FLED = StaticData.BasePlcpointList.First(t => t.id == 75); + if (Agv2FLED != null) + { + if (int.Parse(cardStatus.PosX) >= 119000 && int.Parse(cardStatus.PosX) <= 122800 && (int.Parse(cardStatus.PosY) >= 124100 && int.Parse(cardStatus.PosY) <= 134435)) + { + // Console.WriteLine("=======>2F走廊区域预警"); + + StaticData.PlcDic[0].WriteToPoint(Agv2FLED.plcpointAddress, true, Agv2FLED.plcpointLength.ToString()); + } + else + { + // Console.WriteLine("2F走廊区域正常"); + StaticData.PlcDic[0].WriteToPoint(Agv2FLED.plcpointAddress, false, Agv2FLED.plcpointLength.ToString()); + } + } + + #endregion + } + + + + + } + catch + { + + } + } + + /// + /// 定时更新五楼AGV信息 + /// + private void FiveAgvLogic() + { + try + { + using var scope = host.Services.CreateScope(); + using var dbContext = scope.ServiceProvider.GetRequiredService(); + var baseEquip = StaticData.BaseEquip.First(t => t.objid == 28); + dbContext.ChangeTracker.Clear(); + var basePlcs = StaticData.basePlcs.Where(t => t.Station == "5楼AGV").ToList(); + var wcsCmds = dbContext.WcsTask.Where(t => t.nextPointId == 28).ToList(); + if (wcsCmds.Count > 0) + { + var wcsCmd = wcsCmds.First(); + var endPlc = basePlcs.Where(t => t.Name.Contains("目的地")).First(); + StaticData.PlcDic[2].WriteToPoint(endPlc.Address, wcsCmd.nextPointId.ToString(), endPlc.type); + var startPlc = basePlcs.First(t => t.Name.Contains("起始点")); + StaticData.PlcDic[2].WriteToPoint(startPlc.Address, wcsCmd.currPointId.ToString(), startPlc.type); + var cmdPlc = basePlcs.First(t => t.Name.Contains("任务代号")); + string cmdType = StaticData.BaseDictionary.First(t => t.objid == wcsCmd.taskType).ToPlc; + StaticData.PlcDic[2].WriteToPoint(cmdPlc.Address, cmdType, cmdPlc.type); + } + else + { + var endPlc = basePlcs.Where(t => t.Name.Contains("目的地")).First(); + StaticData.PlcDic[2].WriteToPoint(endPlc.Address, "0", endPlc.type); + var startPlc = basePlcs.First(t => t.Name.Contains("起始点")); + StaticData.PlcDic[2].WriteToPoint(startPlc.Address, "0", startPlc.type); + var cmdPlc = basePlcs.First(t => t.Name.Contains("任务代号")); + StaticData.PlcDic[2].WriteToPoint(cmdPlc.Address, "0", cmdPlc.type); + } + var data = new + { + reqCode = StaticData.SnowId.NextId(), + mapCode = "EE" + }; + string result = HttpHelper.SendPostMessage(baseEquip.serverIp, baseEquip.serverPort.Value, "rcms-dps/rest/queryAgvStatus", data.ToJsonString()); + var reponse = JsonConvert.DeserializeObject(result); + if (reponse != null && reponse.code == "0") + { + var cardStatus = reponse.data.First(t => t.RobotCode == "2034"); + var quantityPlc = basePlcs.First(t => t.Name.Contains("电量")); + StaticData.PlcDic[2].WriteToPoint(quantityPlc.Address, cardStatus.Battery, quantityPlc.type); + var XPlc = basePlcs.First(t => t.Name.Contains('X')); + var Ylc = basePlcs.First(t => t.Name.Contains('Y')); + var status = basePlcs.First(t => t.Name.Contains("Status")); + if (cardStatus.Online.ToLower() == "true") + { + StaticData.PlcDic[2].WriteToPoint(status.Address, cardStatus.Status, status.type); + } + else + { + StaticData.PlcDic[2].WriteToPoint(status.Address, -1, status.type); + } + StaticData.PlcDic[2].WriteToPoint(XPlc.Address, cardStatus.PosX.ToString(), XPlc.type); + StaticData.PlcDic[2].WriteToPoint(Ylc.Address, cardStatus.PosY.ToString(), Ylc.type); + + + basePlcs = StaticData.basePlcs.Where(t => t.Station == "5楼背负式").ToList(); + cardStatus = reponse.data.First(t => t.RobotCode == "6011"); + quantityPlc = basePlcs.First(t => t.Name.Contains("电量")); + StaticData.PlcDic[2].WriteToPoint(quantityPlc.Address, cardStatus.Battery, quantityPlc.type); + XPlc = basePlcs.First(t => t.Name.Contains('X')); + Ylc = basePlcs.First(t => t.Name.Contains('Y')); + status = basePlcs.First(t => t.Name.Contains("Status")); + if (cardStatus.Online.ToLower() == "true") + { + StaticData.PlcDic[2].WriteToPoint(status.Address, cardStatus.Status, status.type); + } + else + { + StaticData.PlcDic[2].WriteToPoint(status.Address, -1, status.type); + } + StaticData.PlcDic[2].WriteToPoint(XPlc.Address, cardStatus.PosX.ToString(), XPlc.type); + StaticData.PlcDic[2].WriteToPoint(Ylc.Address, cardStatus.PosY.ToString(), Ylc.type); + + + basePlcs = StaticData.basePlcs.Where(t => t.Station == "5楼CTU").ToList(); + cardStatus = reponse.data.First(t => t.RobotCode == "8161"); + quantityPlc = basePlcs.First(t => t.Name.Contains("电量")); + StaticData.PlcDic[2].WriteToPoint(quantityPlc.Address, cardStatus.Battery, quantityPlc.type); + XPlc = basePlcs.First(t => t.Name.Contains("X")); + Ylc = basePlcs.First(t => t.Name.Contains("Y")); + status = basePlcs.First(t => t.Name.Contains("Status")); + if (cardStatus.Online.ToLower() == "true") + { + StaticData.PlcDic[2].WriteToPoint(status.Address, cardStatus.Status, status.type); + } + else + { + StaticData.PlcDic[2].WriteToPoint(status.Address, -1, status.type); + } + StaticData.PlcDic[2].WriteToPoint(XPlc.Address, cardStatus.PosX.ToString(), XPlc.type); + StaticData.PlcDic[2].WriteToPoint(Ylc.Address, cardStatus.PosY.ToString(), Ylc.type); + } + } + catch + { + + } + } + + /// + /// 定时更新五楼背负式AGV信息 + /// + private void FiveBearAgvLogic() + { + try + { + using var scope = host.Services.CreateScope(); + using var dbContext = scope.ServiceProvider.GetRequiredService(); + dbContext.ChangeTracker.Clear(); + var basePlcs = StaticData.basePlcs.Where(t => t.Station == "5楼背负式").ToList(); + var wcsCmds = dbContext.WcsTask.Where(t => t.nextPointId == 10).ToList(); + if (wcsCmds.Count > 0) + { + var wcsCmd = wcsCmds.First(); + var endPlc = basePlcs.Where(t => t.Name.Contains("目的地")).First(); + StaticData.PlcDic[2].WriteToPoint(endPlc.Address, wcsCmd.nextPointId.ToString(), endPlc.type); + var startPlc = basePlcs.First(t => t.Name.Contains("起始点")); + StaticData.PlcDic[2].WriteToPoint(startPlc.Address, wcsCmd.currPointId.ToString(), startPlc.type); + var cmdPlc = basePlcs.First(t => t.Name.Contains("任务代号")); + string cmdType = StaticData.BaseDictionary.First(t => t.objid == wcsCmd.taskType).ToPlc; + StaticData.PlcDic[2].WriteToPoint(cmdPlc.Address, cmdType, cmdPlc.type); + } + else + { + var endPlc = basePlcs.Where(t => t.Name.Contains("目的地")).First(); + StaticData.PlcDic[2].WriteToPoint(endPlc.Address, "0", endPlc.type); + var startPlc = basePlcs.First(t => t.Name.Contains("起始点")); + StaticData.PlcDic[2].WriteToPoint(startPlc.Address, "0", startPlc.type); + var cmdPlc = basePlcs.First(t => t.Name.Contains("任务代号")); + StaticData.PlcDic[2].WriteToPoint(cmdPlc.Address, "0", cmdPlc.type); + } + } + catch + { + + } + } + + /// + /// 定时更新五楼CTU信息 + /// + private void CtuCmdLogic() + { + try + { + using var scope = host.Services.CreateScope(); + using var dbContext = scope.ServiceProvider.GetRequiredService(); + var baseEquip = StaticData.BaseEquip.First(t => t.objid == 11); + dbContext.ChangeTracker.Clear(); + var basePlcs = StaticData.basePlcs.Where(t => t.Station == "5楼CTU").ToList(); + var wcsCmds = dbContext.WcsTask.Where(t => t.nextPointId == 11).ToList(); + if (wcsCmds.Count > 0) + { + var wcsCmd = wcsCmds.First(); + List startList = new List(); + List endList = new List(); + if (wcsCmd.taskType != 30) + { + startList.Add(wcsCmd.currPointId); + endList.AddRange(wcsCmds.Select(t => t.nextPointId).ToList()); + } + else + { + startList.Add(wcsCmd.nextPointId); + endList.AddRange(wcsCmds.Select(t => t.currPointId).ToList()); + } + while (endList.Count < 6) + { + endList.Add(0); + } + var endPlcs = basePlcs.Where(t => t.Name.Contains("目的地")).OrderBy(t => t.Name).ToList(); + for (int i = 0; i < endPlcs.Count; i++) + { + StaticData.PlcDic[2].WriteToPoint(endPlcs[i].Address, endList[i].ToString(), endPlcs[i].type); + } + var startPlc = basePlcs.First(t => t.Name.Contains("起始点")); + StaticData.PlcDic[2].WriteToPoint(startPlc.Address, wcsCmd.currPointId.ToString(), startPlc.type); + var cmdPlc = basePlcs.First(t => t.Name.Contains("任务代号")); + string cmdType = StaticData.BaseDictionary.First(t => t.objid == wcsCmd.taskType).ToPlc; + StaticData.PlcDic[2].WriteToPoint(cmdPlc.Address, cmdType, cmdPlc.type); + + } + else + { + var endPlcs = basePlcs.Where(t => t.Name.Contains("目的地")).OrderBy(t => t.Name).ToList(); + for (int i = 0; i < endPlcs.Count; i++) + { + StaticData.PlcDic[2].WriteToPoint(endPlcs[i].Address, "0", endPlcs[i].type); + } + var startPlc = basePlcs.First(t => t.Name.Contains("起始点")); + StaticData.PlcDic[2].WriteToPoint(startPlc.Address, "0", startPlc.type); + var cmdPlc = basePlcs.First(t => t.Name.Contains("任务代号")); + StaticData.PlcDic[2].WriteToPoint(cmdPlc.Address, "0", cmdPlc.type); + } + } + catch + { + + } + } + + /// + /// 定时更新五楼U型线信息 + /// + private void CtuLineLogic() + { + try + { + var basePlcpoints = StaticData.BasePlcpointList.ToList(); + var basePlcs = StaticData.basePlcs.ToList(); + var bill = from a in basePlcpoints + from b in basePlcs + where a.plcpointNo == b.Name && b.Station == "U型线" + select new { a, b }; + foreach (var item in bill) + { + if (item.a.plcpointNo.Contains("RFID")) + { + string? rfid = StaticData.PlcDic[1].ReadRFID(item.a.plcpointAddress); + if (!string.IsNullOrEmpty(rfid)) + { + rfid = rfid[(rfid.IndexOf("C") + 1)..]; + StaticData.PlcDic[2].WriteToPoint(item.b.Address, rfid, item.b.type); + } + else + { + StaticData.PlcDic[2].WriteToPoint(item.b.Address, "0", item.b.type); + } + } + else + { + var value = StaticData.PlcDic[1].Read(item.a.plcpointAddress); + if (value != null && !string.IsNullOrEmpty(value.ToString())) + { + StaticData.PlcDic[2].WriteToPoint(item.b.Address, value.ToString(), item.b.type); + } + else + { + StaticData.PlcDic[2].WriteToPoint(item.b.Address, "0", item.b.type); + } + } + } + } + catch + { + + } + } + + /// + /// 提升机和接驳位信息同步 + /// + private void HositerLogic() + { + try + { + var basePlcpoints = StaticData.BasePlcpointList.ToList(); + var basePlcs = StaticData.basePlcs.ToList(); + var bill = from a in basePlcpoints + from b in basePlcs + where a.plcpointNo == b.Name && b.Station != "U型线" + select new { a, b }; + foreach (var item in bill) + { + if (item.a.plcpointNo.Contains("RFID")) + { + string? rfid = StaticData.PlcDic[0].ReadRFID(item.a.plcpointAddress); + if (!string.IsNullOrEmpty(rfid)) + { + rfid = rfid[(rfid.IndexOf("JYHB") + 4)..]; + StaticData.PlcDic[2].WriteToPoint(item.b.Address, rfid, item.b.type); + } + else + { + StaticData.PlcDic[2].WriteToPoint(item.b.Address, "0", item.b.type); + } + } + else + { + var value = StaticData.PlcDic[0].Read(item.a.plcpointAddress); + if (value != null && !string.IsNullOrEmpty(value.ToString())) + { + StaticData.PlcDic[2].WriteToPoint(item.b.Address, value.ToString(), item.b.type); + } + else + { + StaticData.PlcDic[2].WriteToPoint(item.b.Address, "0", item.b.type); + } + } + } + } + catch + { + + } + } + } + +} + diff --git a/src/Khd.Core.Wcs/Wcs/ThirdFloorAGV.cs b/src/Khd.Core.Wcs/Wcs/ThirdFloorAGV.cs new file mode 100644 index 0000000..f5577f3 --- /dev/null +++ b/src/Khd.Core.Wcs/Wcs/ThirdFloorAGV.cs @@ -0,0 +1,1069 @@ +using Khd.Core.Domain.Dto.TaskType; +using Khd.Core.Domain.Dto.webapi; +using Khd.Core.Domain.Models; +using Khd.Core.EntityFramework; +using Khd.Core.Library; +using Khd.Core.Library.Mapper; +using Khd.Core.Plc.S7; +using Khd.Core.Wcs.Global; +using Masuit.Tools; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; +using Newtonsoft.Json; +using Z.EntityFramework.Plus; + +namespace Khd.Core.Wcs.Wcs +{ + /// + /// 三楼agv调度 + /// + public class ThirdFloorAGV + { + private readonly LoggerUtils _logger = new LoggerUtils(); + private readonly IHost _host; + int FloorNo { get; set; } + private readonly BasePlcpoint putTrayPoint; + private readonly BasePlcpoint getTrayPoint; + private bool IsTrayGet { get; set; } + public ThirdFloorAGV(IHost host, int floor) + { + this._host = host; + FloorNo = floor; + this.putTrayPoint = StaticData.BasePlcpointList.First(t => t.plcpointNo == "putTray"); + this.getTrayPoint = StaticData.BasePlcpointList.First(t => t.plcpointNo == "getTray"); + + } + /// + /// 启动上件扫描监听 + /// + public void StartPoint() + { + + Thread FlowPointThread = new Thread(MonitorInLocatorPoint); + FlowPointThread.Name = "ThirdFloorAGVTrayIn"; + FlowPointThread.IsBackground = true; + FlowPointThread.Start(); + + Thread FZJThread = new Thread(MonitorInFZJPoint); + FZJThread.Name = "ThirdFloorAGV"; + FZJThread.IsBackground = true; + FZJThread.Start(); + + Thread MonitorTraySignalThread = new Thread(MonitorTraySignal); + MonitorTraySignalThread.Name = "ThirdFloorAGVTraySignal"; + MonitorTraySignalThread.IsBackground = true; + MonitorTraySignalThread.Start(); + + Console.WriteLine(DateTime.Now + ":三楼AGV 启动上件扫描监听"); + _logger.Info("三楼AGV 启动上件扫描监听"); + } + + private void MonitorTraySignal() + { + BasePlcpoint GetTrayPoint = StaticData.BasePlcpointList.First(t => t.plcpointNo == "getTray"); + BasePlcpoint GetTrayOverPoint = StaticData.BasePlcpointList.First(t => t.plcpointNo == "GetTrayOver"); + while (true) + { + while (IsTrayGet) + { + try + { + var getTrayValue = StaticData.PlcDic[2].Read(GetTrayPoint.plcpointAddress); + if (getTrayValue != null && !Convert.ToBoolean(getTrayValue)) + { + StaticData.PlcDic[2].WriteToPoint(GetTrayOverPoint.plcpointAddress, false, GetTrayOverPoint.plcpointLength.ToString()); + IsTrayGet = false; + _logger.Info("三楼AGV 托盘已取走信号复位"); + } + } + catch + { + + } + Thread.Sleep(3000); + } + Thread.Sleep(3000); + } + } + + private void MonitorInFZJPoint(object? obj) + { + using var scope = _host.Services.CreateScope(); + using var dbContext = scope.ServiceProvider.GetRequiredService(); + while (true) + { + try + { + dbContext.ChangeTracker.Clear(); + var getTrayValue = StaticData.PlcDic[2].Read(getTrayPoint.plcpointAddress); + if (getTrayValue != null && Convert.ToBoolean(getTrayValue)) + { + var task = dbContext.WcsTask.Where(t => t.IsDelete == 0 || t.IsDelete == null).Where(t => t.taskType == StaticTaskType.ThirdFlipToBin && t.useFlag == 0).FirstOrDefault(); + if (task != null) + { + BaseEquip endEquip = dbContext.BaseEquip.First(t => t.objid == 35); + BaseEquip startEquip = StaticData.BaseEquip.First(t => t.objid == 31); + BaseEquip agvEquip = StaticData.BaseEquip.First(t => t.objid == 9); + //if (endEquip.emptyCount != (SystemData.maxTray / 2) && endEquip.emptyCount != SystemData.maxTray) + if (endEquip.emptyCount < SystemData.maxTray) + { + task.taskType = StaticTaskType.ThirdFlipToBin; + task.useFlag = 1; + task.taskStatus = 0; + task.isEmpty = "1"; + task.qty = 1; + task.nextPointId = agvEquip.objid; + task.nextPointNo = agvEquip.agvPositionCode; + task.currPointId = startEquip.objid; + task.currPointNo = startEquip.agvPositionCode; + task.endPointId = endEquip.objid; + task.endPointNo = endEquip.agvPositionCode; + task.createTime = DateTime.Now; + dbContext.Update(task); + WcsTaskLog wcsTaskLog = CoreMapper.Map(task); + dbContext.Add(wcsTaskLog); + dbContext.SaveChanges(); + _logger.Info("三楼AGV 生成空托盘入收集架任务:" + task.objid); + } + } + } + } + catch (Exception ex) + { + if (ex is PlcException) + { + + } + else + { + _logger.Error(ex.Message + "\n" + ex.StackTrace); + } + } + Thread.Sleep(3000); + } + } + + public void MonitorInLocatorPoint() + { + using var scope = _host.Services.CreateScope(); + using var dbContext = scope.ServiceProvider.GetRequiredService(); + BaseEquip baseEquip = StaticData.BaseEquip.First(t => t.objid == 9); + while (true) + { + try + { + dbContext.ChangeTracker.Clear(); + //获取条码号,如果该条码任务存在就继续任务,如果条码不存在,创建入库任务并调度agv + var taskList = dbContext.WcsTask.Where(t => t.nextPointId == baseEquip.objid).Where(t => t.useFlag == 1).OrderBy(t => t.createTime).ToList(); + foreach (var item in taskList) + { + if (taskList.Where(t => t.objid != item.objid && t.taskStatus > 0).Any()) + { + continue; + } + item.updateTime = DateTime.Now; + if (item.taskStatus == 0) + { + BaseDictionary baseDictionary = StaticData.BaseDictionary.First(t => t.objid == item.taskType); + if (item.taskType == StaticTaskType.ThirdRemove)//移库 + { + var agvTask = new RequestAGVTaskDto + { + reqCode = StaticData.SnowId.NextId().ToString(), + positionCodePath = new List + { + new () + { + positionCode=item.currPointNo, + type="00" + }, + new () + { + positionCode=item.endPointNo, + type="00" + } + }, + taskTyp = baseDictionary.dicValue, + ctnrTyp = "2", + }; + string message = JsonConvert.SerializeObject(agvTask); + string result = HttpHelper.SendPostMessage(baseEquip.serverIp, baseEquip.serverPort.Value, "rcms/services/rest/hikRpcService/genAgvSchedulingTask", message); + var reponseMessage = JsonConvert.DeserializeObject(result); + if (reponseMessage != null && reponseMessage.message == "成功") + { + _logger.Info("三楼楼AGV线程下发任务" + agvTask.ToJsonString() + "\n" + message); + Console.WriteLine(DateTime.Now + ":三楼AGV线程下发任务" + item.currPointNo + "," + item.endPointNo); + item.taskCode = reponseMessage.data; + item.taskStatus = 1; + dbContext.Update(item); + dbContext.WcsTaskLog.Where(t => t.objid == item.objid).Update(t => new WcsTaskLog() { taskStatus = 1 }); + dbContext.SaveChanges(); + } + else + { + _logger.Info("五楼Agv下发任务失败" + item.taskType + result); + } + } + else if (item.taskType == StaticTaskType.ThirdRawIn)//提升机-库位 + { + BaseEquip startEquip = dbContext.BaseEquip.First(t => t.objid == 3); + var agvTask = new RequestAGVTaskDto + { + reqCode = StaticData.SnowId.NextId().ToString(), + positionCodePath = new List + { + new () + { + positionCode=startEquip.agvPositionCode, + type="00" + }, + new () + { + positionCode=item.endPointNo, + type="00" + } + }, + taskTyp = baseDictionary.dicValue, + ctnrTyp = "2", + }; + string message = JsonConvert.SerializeObject(agvTask); + string result = HttpHelper.SendPostMessage(baseEquip.serverIp, baseEquip.serverPort.Value, "rcms/services/rest/hikRpcService/genAgvSchedulingTask", message); + var reponseMessage = JsonConvert.DeserializeObject(result); + if (reponseMessage != null && reponseMessage.message == "成功") + { + _logger.Info("三楼楼AGV线程下发任务" + agvTask.ToJsonString() + "\n" + message); + Console.WriteLine(DateTime.Now + ":三楼AGV线程下发任务" + item.currPointNo + "," + item.endPointNo); + item.taskCode = reponseMessage.data; + item.taskStatus = 1; + dbContext.Update(item); + dbContext.WcsTaskLog.Where(t => t.objid == item.objid).Update(t => new WcsTaskLog() { taskStatus = 1 }); + dbContext.SaveChanges(); + } + else + { + _logger.Info("三楼Agv下发任务失败" + item.taskType + result); + } + } + else if (item.taskType == StaticTaskType.ThirdRawToFlip)//库位-翻转机 + { + BasePlcpoint basePlcpoint = StaticData.BasePlcpointList.First(t => t.plcpointNo == "putTray"); + var callMaterial = StaticData.PlcDic[2].Read(basePlcpoint.plcpointAddress); + if (callMaterial != null && Convert.ToBoolean(callMaterial)) + { + WmsRawOutstock? wmsRawOutstock = dbContext.WmsRawOutstock.FirstOrDefault(t => t.rawOutstockId == item.orderId ); //&& t.executeStatus == "0" + if (wmsRawOutstock != null) + { + wmsRawOutstock.executeStatus = "1"; + wmsRawOutstock.updateDate = DateTime.Now; + BaseEquip endEquip = StaticData.BaseEquip.First(t => t.objid == 31); + WmsBaseLocation wmsBaseLocation = dbContext.WmsBaseLocation.First(t => t.locationId == item.currPointId); + + var agvTask = new RequestAGVTaskDto + { + reqCode = StaticData.SnowId.NextId().ToString(), + positionCodePath = new List + { + new () + { + positionCode=wmsBaseLocation.agvPositionCode, + type="00" + }, + new () + { + positionCode=endEquip.agvPositionCode, + type="00" + } + }, + taskTyp = baseDictionary.dicValue, + ctnrTyp = "2", + }; + string message = JsonConvert.SerializeObject(agvTask); + string result = HttpHelper.SendPostMessage(baseEquip.serverIp, baseEquip.serverPort.Value, "rcms/services/rest/hikRpcService/genAgvSchedulingTask", message); + var reponseMessage = JsonConvert.DeserializeObject(result); + if (reponseMessage != null && reponseMessage.message == "成功") + { + _logger.Info("三楼楼AGV线程下发任务" + agvTask.ToJsonString() + "\n" + message); + Console.WriteLine(DateTime.Now + ":三楼AGV线程下发任务" + item.currPointNo + "," + item.endPointNo); + item.taskCode = reponseMessage.data; + item.taskStatus = 1; + dbContext.Update(wmsRawOutstock); + dbContext.Update(item); + dbContext.WcsTaskLog.Where(t => t.objid == item.objid).Update(t => new WcsTaskLog() { taskStatus = 1 }); + dbContext.SaveChanges(); + } + else + { + _logger.Info("三楼Agv下发任务失败" + item.taskType + result); + } + } + } + } + else if (item.taskType == StaticTaskType.ThirdTransitToBin)//周转位-收集架 + { + BaseEquip startEquip = dbContext.BaseEquip.First(t => t.objid == item.currPointId); + BaseEquip endEquip = dbContext.BaseEquip.First(t => t.objid == item.endPointId); + var agvTask = new RequestAGVTaskDto + { + reqCode = StaticData.SnowId.NextId().ToString().ToString(), + positionCodePath = new List + { + new () + { + positionCode= startEquip.agvPositionCode, + type="00" + }, + new () + { + positionCode=endEquip.agvPositionCode, + type="00" + } + }, + taskTyp = baseDictionary.dicValue, + ctnrTyp = "2", + ctnrNum = startEquip.emptyCount.ToString() + }; + string message = JsonConvert.SerializeObject(agvTask); + string result = HttpHelper.SendPostMessage(baseEquip.serverIp, baseEquip.serverPort.Value, "rcms/services/rest/hikRpcService/genAgvSchedulingTask", message); + var reponseMessage = JsonConvert.DeserializeObject(result); + if (reponseMessage != null && reponseMessage.message == "成功") + { + _logger.Info("三楼楼AGV线程下发任务" + agvTask.ToJsonString() + "\n" + message); + Console.WriteLine(DateTime.Now + ":三楼AGV线程下发任务" + item.currPointNo + "," + item.endPointNo); + item.taskCode = reponseMessage.data; + item.taskStatus = 1; + dbContext.Update(item); + dbContext.WcsTaskLog.Where(t => t.objid == item.objid).Update(t => new WcsTaskLog() { taskStatus = 1 }); + dbContext.SaveChanges(); + } + else + { + _logger.Info("三楼Agv下发任务失败" + item.taskType + result); + } + } + else if (item.taskType == StaticTaskType.ThirdFlipToBin)//翻转机-收集架 + { + BaseEquip startEquip = dbContext.BaseEquip.First(t => t.objid == item.currPointId); + BaseEquip endEquip = dbContext.BaseEquip.First(t => t.objid == item.endPointId); + var agvTask = new RequestAGVTaskDto + { + reqCode = StaticData.SnowId.NextId().ToString().ToString(), + positionCodePath = new List + { + new () + { + positionCode=startEquip.agvPositionCode, + type="00" + }, + new () + { + positionCode=endEquip.agvPositionCode, + type="00" + } + }, + taskTyp = baseDictionary.dicValue, + ctnrTyp = "2", + ctnrNum = "1" + }; + string message = JsonConvert.SerializeObject(agvTask); + string result = HttpHelper.SendPostMessage(baseEquip.serverIp, baseEquip.serverPort.Value, "rcms/services/rest/hikRpcService/genAgvSchedulingTask", message); + var reponseMessage = JsonConvert.DeserializeObject(result); + if (reponseMessage != null && reponseMessage.message == "成功") + { + _logger.Info("三楼楼AGV线程下发任务" + agvTask.ToJsonString() + "\n" + message); + Console.WriteLine(DateTime.Now + ":三楼AGV线程下发任务" + item.currPointNo + "," + item.endPointNo); + item.taskCode = reponseMessage.data; + item.taskStatus = 1; + dbContext.Update(item); + dbContext.WcsTaskLog.Where(t => t.objid == item.objid).Update(t => new WcsTaskLog() { taskStatus = 1 }); + dbContext.SaveChanges(); + } + else + { + _logger.Info("三楼Agv下发任务失败" + item.taskType + result); + } + } + else if (item.taskType == StaticTaskType.ThirdBinToTransit)//收集架-周转区 + { + BaseEquip startEquip = dbContext.BaseEquip.First(t => t.objid == item.currPointId); + BaseEquip endEquip = dbContext.BaseEquip.First(t => t.objid == item.endPointId); + + var agvTask = new RequestAGVTaskDto + { + reqCode = StaticData.SnowId.NextId().ToString().ToString(), + positionCodePath = new List + { + new () + { + positionCode=startEquip.agvPositionCode, + type="00" + }, + new () + { + positionCode=endEquip.agvPositionCode, + type="00" + } + }, + taskTyp = baseDictionary.dicValue, + ctnrTyp = "2", + ctnrNum = startEquip.emptyCount.ToString() + }; + string message = JsonConvert.SerializeObject(agvTask); + string result = HttpHelper.SendPostMessage(baseEquip.serverIp, baseEquip.serverPort.Value, "rcms/services/rest/hikRpcService/genAgvSchedulingTask", message); + var reponseMessage = JsonConvert.DeserializeObject(result); + if (reponseMessage != null && reponseMessage.message == "成功") + { + _logger.Info("三楼楼AGV线程下发任务" + agvTask.ToJsonString() + "\n" + message); + Console.WriteLine(DateTime.Now + ":三楼AGV线程下发任务" + item.currPointNo + "," + item.endPointNo); + item.taskCode = reponseMessage.data; + item.taskStatus = 1; + dbContext.Update(item); + dbContext.WcsTaskLog.Where(t => t.objid == item.objid).Update(t => new WcsTaskLog() { taskStatus = 1 }); + dbContext.SaveChanges(); + } + else + { + _logger.Info("三楼Agv下发任务失败" + item.taskType + result); + } + } + else if (item.taskType == StaticTaskType.ThirdTransitToLift)//周转区-提升机 + { + BaseEquip startEquip = dbContext.BaseEquip.First(t => t.objid == item.currPointId); + BaseEquip lineEquip = dbContext.BaseEquip.First(t => t.objid == 3); + if (lineEquip.equipStatus == 0) + { + var agvTask = new RequestAGVTaskDto + { + reqCode = StaticData.SnowId.NextId().ToString().ToString(), + positionCodePath = new List + { + new() + { + positionCode =startEquip.agvPositionCode, + type = "00" + }, + new() + { + positionCode = lineEquip.equipNo, + type = "00" + } + }, + taskTyp = baseDictionary.dicValue, + ctnrTyp = "2", + ctnrNum = startEquip.emptyCount.ToString() + }; + string message = JsonConvert.SerializeObject(agvTask); + string result = HttpHelper.SendPostMessage(baseEquip.serverIp, baseEquip.serverPort.Value, "rcms/services/rest/hikRpcService/genAgvSchedulingTask", message); + var reponseMessage = JsonConvert.DeserializeObject(result); + if (reponseMessage != null && reponseMessage.message == "成功") + { + _logger.Info("三楼楼AGV线程下发任务" + agvTask.ToJsonString() + "\n" + message); + Console.WriteLine(DateTime.Now + ":三楼AGV线程下发任务" + item.currPointNo + "," + item.endPointNo); + item.taskCode = reponseMessage.data; + item.taskStatus = 1; + lineEquip.equipStatus = 1; + dbContext.Update(lineEquip); + dbContext.Update(item); + dbContext.WcsTaskLog.Where(t => t.objid == item.objid).Update(t => new WcsTaskLog() { taskStatus = 1 }); + dbContext.SaveChanges(); + } + else + { + _logger.Info("三楼Agv下发任务失败" + item.taskType + result); + } + } + else + { + continue; + } + } + else if (item.taskType == StaticTaskType.ThirdTransitToSecond)//三楼空托盘转运到二楼 + { + BaseEquip lineEquip = dbContext.BaseEquip.First(t => t.objid == 3); + BaseEquip startEquip = dbContext.BaseEquip.First(t => t.objid == item.currPointId); + if (lineEquip.equipStatus == 0) + { + var agvTask = new RequestAGVTaskDto + { + reqCode = StaticData.SnowId.NextId().ToString().ToString(), + positionCodePath = new List + { + new() + { + positionCode = startEquip.agvPositionCode, + type = "00" + }, + new() + { + positionCode = lineEquip.equipNo, + type = "00" + } + }, + taskTyp = baseDictionary.dicValue, + ctnrTyp = "2", + ctnrNum = startEquip.emptyCount.ToString() + }; + string message = JsonConvert.SerializeObject(agvTask); + string result = HttpHelper.SendPostMessage(baseEquip.serverIp, baseEquip.serverPort.Value, "rcms/services/rest/hikRpcService/genAgvSchedulingTask", message); + var reponseMessage = JsonConvert.DeserializeObject(result); + if (reponseMessage != null && reponseMessage.message == "成功") + { + _logger.Info("三楼楼AGV线程下发任务" + agvTask.ToJsonString() + "\n" + message); + Console.WriteLine(DateTime.Now + ":三楼AGV线程下发任务" + item.currPointNo + "," + item.endPointNo); + item.taskCode = reponseMessage.data; + item.taskStatus = 1; + lineEquip.equipStatus = 1; + dbContext.Update(lineEquip); + dbContext.Update(item); + dbContext.WcsTaskLog.Where(t => t.objid == item.objid).Update(t => new WcsTaskLog() { taskStatus = 1 }); + dbContext.SaveChanges(); + } + else + { + _logger.Info("三楼Agv下发任务失败" + item.taskType + result); + } + } + else + { + continue; + } + } + else if (item.taskType == StaticTaskType.ThirdStockReturnTask) + { + BaseEquip lineEquip = dbContext.BaseEquip.First(t => t.objid == 3); + if (lineEquip.equipStatus == 0) + { + var agvTask = new RequestAGVTaskDto + { + reqCode = StaticData.SnowId.NextId().ToString().ToString(), + positionCodePath = new List + { + new () + { + positionCode=item.currPointNo, + type="00" + }, + new () + { + positionCode=item.endPointNo, + type="00" + } + }, + taskTyp = baseDictionary.dicValue, + ctnrTyp = "2", + ctnrNum = "1" + }; + string message = JsonConvert.SerializeObject(agvTask); + string result = HttpHelper.SendPostMessage(baseEquip.serverIp, baseEquip.serverPort.Value, "rcms/services/rest/hikRpcService/genAgvSchedulingTask", message); + var reponseMessage = JsonConvert.DeserializeObject(result); + if (reponseMessage != null && reponseMessage.message == "成功") + { + _logger.Info("三楼楼AGV线程下发任务" + agvTask.ToJsonString() + "\n" + message); + Console.WriteLine(DateTime.Now + ":三楼AGV线程下发任务" + item.currPointNo + "," + item.endPointNo); + item.taskCode = reponseMessage.data; + item.taskStatus = 1; + lineEquip.equipStatus = 1; + dbContext.Update(lineEquip); + dbContext.Update(item); + dbContext.WcsTaskLog.Where(t => t.objid == item.objid).Update(t => new WcsTaskLog() { taskStatus = 1 }); + dbContext.SaveChanges(); + } + else + { + _logger.Info("三楼Agv下发任务失败" + item.taskType + result); + } + } + else + { + continue; + } + } + } + else + { + { + if (item.taskStatus == 3) + { + if (item.currPointId == 3)//从提升机开始 + { + BasePlcpoint lineSignal = StaticData.BasePlcpointList.First(t => t.plcpointNo == "linesignal03"); + BasePlcpoint Rfid = StaticData.BasePlcpointList.First(t => t.plcpointNo == "RFID003"); + var lineSignalValue = StaticData.PlcDic[0].Read(lineSignal.plcpointAddress); + var RfidValue = StaticData.PlcDic[0].ReadRFID(Rfid.plcpointAddress); + if (lineSignalValue == null || item.containerNo != RfidValue || Convert.ToInt32(lineSignalValue) == 0) + { + _logger.Info($"三楼Agv继续任务失败,所取货物与任务不符,任务货物为{item.containerNo},RFID为{RfidValue},线路信号为{lineSignalValue}"); + Console.WriteLine($"{DateTime.Now}:三楼Agv继续任务失败,所取货物与任务不符,任务货物为{item.containerNo},RFID为{RfidValue},线路信号为{lineSignalValue}"); + Thread.Sleep(1000); + continue; + } + } + if (item.endPointId == 3) + { + BasePlcpoint lineSignal = StaticData.BasePlcpointList.First(t => t.plcpointNo == "linesignal03"); + var wcsrun = StaticData.PlcDic[0].Read(StaticData.BasePlcpointList.First(t => t.plcpointNo == "wcsrun03").plcpointAddress); + var lineSignalValue = StaticData.PlcDic[0].Read(lineSignal.plcpointAddress); + if (lineSignalValue == null || Convert.ToInt32(lineSignalValue) == 1 || wcsrun == null || wcsrun.ToString() != "0") + { + _logger.Info($"三楼Agv继续任务失败,提升机有货物"); + Console.WriteLine($"{DateTime.Now}:三楼Agv继续任务失败,提升机有货物"); + Thread.Sleep(1000); + continue; + } + } + if (item.endPointId == 31)//如果终点是翻转机的任务,有东西则跳过 + { + BasePlcpoint basePlcpoint = StaticData.BasePlcpointList.First(t => t.plcpointNo == "putTray"); + var callMaterial = StaticData.PlcDic[2].Read(basePlcpoint.plcpointAddress); + if (callMaterial == null || !Convert.ToBoolean(callMaterial)) + { + _logger.Info($"三楼Agv继续任务失败,无法判断翻转机上是否有物料,丢失3楼翻转机信号"); + Console.WriteLine($"{DateTime.Now}:三楼Agv继续任务失败,无法判断翻转机上是否有物料,丢失3楼翻转机信号"); + Thread.Sleep(1000); + continue; + } + } + if(item.taskType == StaticTaskType.ThirdFlipToBin) //终点是托盘收集架 + { + BasePlcpoint basePlcpoint1 = StaticData.BasePlcpointList.First(t => t.plcpointNo == "GetTrayOver"); + StaticData.PlcDic[2].WriteToPoint(basePlcpoint1.plcpointAddress, true, basePlcpoint1.plcpointLength.ToString()); + IsTrayGet = true; + _logger.Info("通知PLC已经取走信号:true"); + + } + + var agvTask = new RequestAGVTaskDto + { + reqCode = StaticData.SnowId.NextId().ToString().ToString(), + taskCode = item.taskCode + }; + string message = JsonConvert.SerializeObject(agvTask); + string result = HttpHelper.SendPostMessage(baseEquip.serverIp, baseEquip.serverPort.Value, "rcms/services/rest/hikRpcService/continueTask", message); + ReponseMessage? reponseMessage = JsonConvert.DeserializeObject(result); + if (reponseMessage != null && reponseMessage.message == "成功") + { + dbContext.WcsTask.Where(t => t.objid == item.objid).Update(t => new WcsTask() { taskStatus = 4 }); + dbContext.WcsTaskLog.Where(t => t.objid == item.objid).Update(t => new WcsTaskLog() { taskStatus = 4 }); + } + } + else if (item.taskStatus == 5)//任务完成 + { + if (item.currPointId == 3)//从接驳位出发 + { + BaseEquip lineEquip = dbContext.BaseEquip.First(t => t.objid == 3); + lineEquip.equipStatus = 0; + dbContext.Update(lineEquip); + } + if (item.taskType == StaticTaskType.ThirdRemove)//移库 + { + var wmsRawStock = dbContext.WmsRawStock.Where(t => t.locationCode == item.currPointNo).FirstOrDefault(); + WmsBaseLocation wmsBaseLocation = dbContext.WmsBaseLocation.Where(t => t.locationId == item.currPointId).First(); + WmsBaseLocation toLocation = dbContext.WmsBaseLocation.Where(t => t.locationId == item.endPointId).First(); + dbContext.WmsBaseLocation.Where(t => t.locationId == wmsBaseLocation.locationId) + .Update(t => new WmsBaseLocation() { containerCode = null, updateTime = DateTime.Now, locationStatus = "1" }); + dbContext.WmsBaseLocation.Where(t => t.locationId == toLocation.locationId) + .Update(t => new WmsBaseLocation { containerCode = item.containerNo, updateTime = DateTime.Now, locationStatus = "1" }); + + SystemData.UnLockOutLocation(wmsBaseLocation, dbContext); + SystemData.UnLockOutLocation(toLocation, dbContext); + if (wmsRawStock != null) + { + wmsRawStock.locationCode = item.endPointNo; + dbContext.Update(wmsRawStock); + } + + + dbContext.Remove(item); + dbContext.WcsTaskLog.Where(t => t.objid == item.objid).Update(t => new WcsTaskLog() { taskStatus = 6 }); + + #region 插入移库记录 + var wmsMove = dbContext.WmsMove.Where(t => t.MoveId == item.orderId).FirstOrDefault(); + if (wmsMove == null) + { + wmsMove = new WmsMove(); + wmsMove.MoveId = StaticData.SnowId.NextId(); + wmsMove.TaskCode = StaticData.SnowId.NextId().ToString(); + wmsMove.WarehouseId = wmsBaseLocation.warehouseId; + wmsMove.OriLocationCode = wmsBaseLocation.locationCode; + wmsMove.TargetLocationCode = toLocation.locationCode; + wmsMove.InstockBatch = wmsRawStock.instockBatch; + wmsMove.MaterialId = wmsRawStock.materialId; + wmsMove.PlanAmount = 1; + wmsMove.RealOutstockAmount = 1; + wmsMove.RealInstockAmount = 1; + wmsMove.OperationType = "3"; + wmsMove.MoveWay = "2"; + wmsMove.MoveType = "1"; + wmsMove.AuditStatus = "1"; + wmsMove.ExecuteStatus = "2"; + wmsMove.UpdateBy = "WCS"; + wmsMove.UpdateDate = DateTime.Now; + wmsMove.BeginTime = DateTime.Now; + wmsMove.EndTime = DateTime.Now; + dbContext.WmsMove.Add(wmsMove); + } + else + { + wmsMove.RealOutstockAmount += 1; + wmsMove.EndTime = DateTime.Now; + wmsMove.UpdateDate = DateTime.Now; + wmsMove.UpdateBy = "WCS"; + wmsMove.ExecuteStatus = "2"; + dbContext.Update(wmsMove); + } + WmsMoveDetail wmsMoveDetail = new WmsMoveDetail(); + wmsMoveDetail.MoveId = wmsMove.MoveId; + wmsMoveDetail.MaterialBarcode = wmsMove.InstockBatch; + wmsMoveDetail.InstockBatch = wmsMove.InstockBatch; + wmsMoveDetail.MaterialId = (long)wmsRawStock.materialId; + wmsMoveDetail.LocationCode = toLocation.locationCode; + wmsMoveDetail.PlanAmount = 1; + wmsMoveDetail.RealInstockAmount = 1; + wmsMoveDetail.RealAmount = 1; + wmsMoveDetail.ExecuteStatus = "2"; + wmsMoveDetail.ExecuteTime = DateTime.Now; + wmsMoveDetail.ExecuteEndTime = DateTime.Now; + wmsMoveDetail.ExecutePerson = "WCS"; + wmsMoveDetail.UpdateBy = "WCS"; + wmsMoveDetail.UpdateDate = DateTime.Now; + + dbContext.WmsMoveDetail.Add(wmsMoveDetail); + #endregion + + dbContext.SaveChanges(); + SystemData.SendPlcLocation(wmsBaseLocation); + SystemData.SendPlcLocation(toLocation); + + + } + else if (item.taskType == StaticTaskType.ThirdRawIn)//入库 + { + WmsBaseLocation wmsBaseLocation = dbContext.WmsBaseLocation + .First(t => t.locationId == item.endPointId && t.warehouseFloor == 3); + wmsBaseLocation.locationStatus = "1"; + wmsBaseLocation.containerCode = item.containerNo; + wmsBaseLocation.updateTime = DateTime.Now; + wmsBaseLocation.updateBy = "WCS"; + var mesBasePalletInfo = dbContext.MesBasePalletInfo.FirstOrDefault(t => t.palletInfoCode == item.containerNo); + if (mesBasePalletInfo != null) + { + var mesBaseBarcodeInfo = dbContext.MesBaseBarcodeInfo.FirstOrDefault(t => t.barcodeInfo == mesBasePalletInfo.materialBarcode); + if (mesBaseBarcodeInfo != null) + { + var wmsRawStock = new WmsRawStock() + { + rawStockId = StaticData.SnowId.NextId(), + activeFlag = "1", + saleOrderId = mesBaseBarcodeInfo.saleOrderId == null ? 0 : mesBaseBarcodeInfo.saleOrderId, + stockType = "1", + supplierId = mesBaseBarcodeInfo.manufacturerId, + qualityStatus = "1", + completeFlag = "1", + createBy = "WCS", + createDate = DateTime.Now, + frozenAmount = 0, + instockBatch = mesBaseBarcodeInfo.barcodeInfo, + instockDate = DateTime.Now, + locationCode = wmsBaseLocation.locationCode, + materialId = mesBaseBarcodeInfo.materialId, + occupyAmount = 0, + palletInfoCode = item.containerNo, + safeFlag = mesBaseBarcodeInfo.safeFlag, + totalAmount = 1, + warehouseFloor = 3, + warehouseId = 311 + }; + WmsRawInstock wmsRawInstock = new WmsRawInstock() + { + taskCode = item.taskCode, + materialBarCode = mesBaseBarcodeInfo.barcodeInfo, + materialBatchCode = mesBaseBarcodeInfo.batchCode, + applyBy = "wcs", + applyDate = System.DateTime.Now, + purchaseOrderId = mesBaseBarcodeInfo.PurchaseOrderId, + + beginTime = System.DateTime.Now, + endTime = DateTime.Now, + locationCode = wmsBaseLocation.locationCode, + executeStatus = "2", + instockAmount = 1, + instockType = item.fromFloorNo == 1 ? "1" : "3", + + materialId = mesBaseBarcodeInfo.materialId, + operationType = "3", + palletInfoCode = mesBaseBarcodeInfo.palletInfoCode, + poNo = mesBaseBarcodeInfo.poNo, + warehouseId = 311 + }; + SystemData.UnLockOutLocation(wmsBaseLocation, dbContext); + dbContext.Add(wmsRawInstock); + dbContext.Add(wmsRawStock); + dbContext.Update(wmsBaseLocation); + dbContext.Remove(item); + dbContext.WcsTaskLog.Where(t => t.objid == item.objid).Update(t => new WcsTaskLog { taskStatus = 6 }); + dbContext.SaveChanges(); + SystemData.SendPlcLocation(wmsBaseLocation); + + } + } + } + else if (item.taskType == StaticTaskType.ThirdTransitToBin)//周转区-收集架,暂不使用 + { + BaseEquip startEquip = dbContext.BaseEquip.First(t => t.objid == item.currPointId); + BaseEquip endEquip = dbContext.BaseEquip.First(t => t.objid == item.endPointId); + startEquip.emptyCount = 0; + startEquip.equipStatus = 0; + startEquip.updateTime = DateTime.Now; + startEquip.updateBy = "WCS"; + endEquip.emptyCount += item.qty; + endEquip.equipStatus = 1; + endEquip.updateTime = DateTime.Now; + endEquip.updateBy = "WCS"; + dbContext.Update(startEquip); + dbContext.Update(endEquip); + dbContext.Remove(item); + dbContext.WcsTaskLog.Where(t => t.objid == item.objid).Update(t => new WcsTaskLog { taskStatus = 6 }); + dbContext.SaveChanges(); + } + else if (item.taskType == StaticTaskType.ThirdRawToFlip)//原材料出库 + { + WmsBaseLocation wmsBaseLocation = dbContext.WmsBaseLocation + .First(t => t.locationId == item.currPointId); + wmsBaseLocation.locationStatus = "1"; + wmsBaseLocation.containerCode = null; + wmsBaseLocation.updateTime = DateTime.Now; + wmsBaseLocation.updateBy = "WCS"; + + WmsRawOutstock? wmsRawOutstock = dbContext.WmsRawOutstock.FirstOrDefault(t => t.rawOutstockId == item.orderId); + WmsRawStock? wmsRawStock = dbContext.WmsRawStock.Where(t => t.locationCode == item.currPointNo).FirstOrDefault(); + + if (wmsRawStock != null) + { + MesBaseBarcodeInfo? mesBaseBarcodeInfo = dbContext.MesBaseBarcodeInfo.Where(t => t.barcodeInfo == wmsRawStock.instockBatch).FirstOrDefault(); + WmsRawOutstockDetail newWmsRawOutstockDetail = new WmsRawOutstockDetail(); + if (wmsRawOutstock != null) + { + wmsRawOutstock.realOutstockAmount += 1; + if (wmsRawOutstock.realOutstockAmount >= wmsRawOutstock.outstockAmount) + { + wmsRawOutstock.endTime = DateTime.Now; + wmsRawOutstock.executeStatus = "2"; + } + + } + //else + //{ + // wmsRawOutstock = new WmsRawOutstock() + // { + // rawOutstockId = StaticData.SnowId.NextId(), + // warehouseId = 311, + // taskCode = "", + // outstockAmount = 1, + // realOutstockAmount = 1, + // operationType = "3", + // taskType = "1", + // auditStatus = "0", + // executeStatus = "2", + // saleOrderId = mesBaseBarcodeInfo != null ? mesBaseBarcodeInfo.saleOrderId : 0, + // }; + + //} + newWmsRawOutstockDetail.rawOutstockId = wmsRawOutstock.rawOutstockId; + newWmsRawOutstockDetail.taskCode = wmsRawOutstock.taskCode; + newWmsRawOutstockDetail.warehouseId = wmsRawOutstock.warehouseId; + newWmsRawOutstockDetail.locationCode = wmsRawStock.locationCode; + newWmsRawOutstockDetail.materialBarcode = wmsRawStock.instockBatch; + newWmsRawOutstockDetail.materialId = wmsRawStock.materialId; + if (mesBaseBarcodeInfo != null) + { + newWmsRawOutstockDetail.instockBatch = mesBaseBarcodeInfo.batchCode; + newWmsRawOutstockDetail.materialProductionDate = mesBaseBarcodeInfo.productionDate; + } + newWmsRawOutstockDetail.planAmount = wmsRawOutstock.outstockAmount; + newWmsRawOutstockDetail.outstockAmount = wmsRawOutstock.realOutstockAmount; + newWmsRawOutstockDetail.executeStatus = "2"; + newWmsRawOutstockDetail.outstockPerson = wmsRawOutstock.applyBy; + newWmsRawOutstockDetail.outstockTime = DateTime.Now; + newWmsRawOutstockDetail.outstockWay = "2"; + newWmsRawOutstockDetail.createBy = "WCS"; + newWmsRawOutstockDetail.createDate = DateTime.Now; + newWmsRawOutstockDetail.stackAmount = 1; + dbContext.Add(newWmsRawOutstockDetail); + dbContext.Update(wmsRawOutstock); + + + BaseEquip endEquip = dbContext.BaseEquip.First(t => t.objid == 31); + endEquip.emptyCount = 1; + + SystemData.UnLockOutLocation(wmsBaseLocation, dbContext); + dbContext.Update(endEquip); + dbContext.Remove(wmsRawStock); + dbContext.Update(wmsBaseLocation); + WcsTask wcsTask = CoreMapper.Map(item); + wcsTask.objid = StaticData.SnowId.NextId(); + wcsTask.taskStatus = 0; + wcsTask.useFlag = 0; + wcsTask.taskType = StaticTaskType.ThirdFlipToBin; + wcsTask.createBy = "WCS"; + wcsTask.createTime = DateTime.Now; + dbContext.Remove(item); + dbContext.Add(wcsTask); + dbContext.WcsTaskLog.Where(t => t.objid == item.objid).Update(t => new WcsTaskLog { taskStatus = 6 }); + dbContext.SaveChanges(); + SystemData.SendPlcLocation(wmsBaseLocation); + + + } + } + else if (item.taskType == StaticTaskType.ThirdFlipToBin)//翻转机就到收集架 + { + MesBasePalletInfo? mesBasePalletInfo = dbContext.MesBasePalletInfo.FirstOrDefault(t => t.palletInfoCode == item.containerNo); + if (mesBasePalletInfo != null) + { + + MesBaseBarcodeInfo? mesBaseBarcodeInfo = dbContext.MesBaseBarcodeInfo.Where(t => t.palletInfoCode == item.containerNo).FirstOrDefault(); + if (mesBaseBarcodeInfo != null) + { + mesBaseBarcodeInfo.palletInfoCode = null; + dbContext.Update(mesBaseBarcodeInfo); + } + mesBasePalletInfo.bindAmount = null; + mesBasePalletInfo.materialBarcode = null; + mesBasePalletInfo.materialCode = null; + mesBasePalletInfo.materialId = null; + mesBasePalletInfo.materialName = null; + mesBasePalletInfo.updateBy = "WCS"; + mesBasePalletInfo.updateTime = DateTime.Now; + dbContext.Update(mesBasePalletInfo); + BaseEquip emptyEquip = dbContext.BaseEquip.First(t => t.objid == 35); + BaseEquip endEquip = dbContext.BaseEquip.First(t => t.objid == 31); + endEquip.emptyCount = 0; + dbContext.Update(endEquip); + emptyEquip.emptyCount += 1; + emptyEquip.equipStatus = 1; + emptyEquip.updateTime = DateTime.Now; + emptyEquip.updateBy = "WCS"; + dbContext.Update(emptyEquip); + dbContext.Remove(item); + dbContext.WcsTaskLog.Where(t => t.objid == item.objid).Update(t => new WcsTaskLog { taskStatus = 6 }); + dbContext.SaveChanges(); + + } + } + else if (item.taskType == StaticTaskType.ThirdBinToTransit)//收集架-周转区 + { + BaseEquip emptyEquip = dbContext.BaseEquip.First(t => t.objid == 35); + BaseEquip endEquip = dbContext.BaseEquip.First(t => t.objid == item.endPointId); + emptyEquip.emptyCount = 0; + emptyEquip.updateTime = DateTime.Now; + emptyEquip.updateBy = "WCS"; + endEquip.emptyCount = item.qty; + endEquip.equipStatus = 1; + endEquip.updateTime = DateTime.Now; + endEquip.updateBy = "WCS"; + dbContext.Update(endEquip); + dbContext.Update(emptyEquip); + dbContext.Remove(item); + dbContext.WcsTaskLog.Where(t => t.objid == item.objid).Update(t => new WcsTaskLog { taskStatus = 6 }); + dbContext.SaveChanges(); + } + else if (item.taskType == StaticTaskType.ThirdTransitToLift || item.taskType == StaticTaskType.ThirdTransitToSecond)//周转区-提升机 + { + BaseEquip startEquip = dbContext.BaseEquip.First(t => t.objid == item.currPointId); + BaseEquip lineEquip = StaticData.BaseEquip.First(t => t.objid == 3); + startEquip.emptyCount = 0; + startEquip.equipStatus = 0; + startEquip.updateTime = DateTime.Now; + startEquip.updateBy = "WCS"; + dbContext.Update(startEquip); + BaseEquip endEquip = StaticData.BaseEquip.First(t => t.objid == item.endPointId); + item.nextPointId = lineEquip.objid; + item.nextPointNo = lineEquip.equipNo; + item.fromFloorNo = 3; + item.floorNo = endEquip.floorNo; + item.taskStatus = 6; + dbContext.Update(item); + dbContext.WcsTaskLog.Where(t => t.objid == item.objid).Update(t => new WcsTaskLog { taskStatus = 6 }); + dbContext.SaveChanges(); + } + else if (item.taskType == StaticTaskType.ThirdStockReturnTask) + { + BaseEquip floorLineEquip = StaticData.BaseEquip.First(t => t.objid == 3); + var wmsRawOutstock = dbContext.WmsRawOutstock.Where(t => t.rawOutstockId == item.orderId).FirstOrDefault(); + var wmsRawStock = dbContext.WmsRawStock.Where(t => t.locationCode == item.currPointNo).FirstOrDefault(); + var wmsBaseLocation = dbContext.WmsBaseLocation.Where(t => t.locationCode == item.currPointNo).FirstOrDefault(); + if (wmsRawOutstock != null && wmsRawStock != null && wmsBaseLocation != null) + { + + wmsRawOutstock.realOutstockAmount += 1; + wmsRawOutstock.executeStatus = "2"; + wmsRawOutstock.endTime = DateTime.Now; + + WmsRawOutstockDetail newWmsRawOutstockDetail = new WmsRawOutstockDetail(); + newWmsRawOutstockDetail.rawOutstockId = wmsRawOutstock.rawOutstockId; + newWmsRawOutstockDetail.taskCode = wmsRawOutstock.taskCode; + newWmsRawOutstockDetail.warehouseId = wmsRawOutstock.warehouseId; + newWmsRawOutstockDetail.locationCode = wmsRawOutstock.locationCode; + newWmsRawOutstockDetail.materialBarcode = wmsRawOutstock.materialBatch; + newWmsRawOutstockDetail.materialId = wmsRawOutstock.materialId; + MesBaseBarcodeInfo? mesBaseBarcodeInfo = dbContext.MesBaseBarcodeInfo.Where(t => t.barcodeInfo == wmsRawStock.instockBatch).FirstOrDefault(); + if (mesBaseBarcodeInfo != null) + { + newWmsRawOutstockDetail.instockBatch = mesBaseBarcodeInfo.batchCode; + newWmsRawOutstockDetail.materialProductionDate = mesBaseBarcodeInfo.productionDate; + } + newWmsRawOutstockDetail.planAmount = wmsRawOutstock.outstockAmount; + newWmsRawOutstockDetail.outstockAmount = wmsRawOutstock.realOutstockAmount; + newWmsRawOutstockDetail.executeStatus = "2"; + newWmsRawOutstockDetail.outstockPerson = wmsRawOutstock.applyBy; + newWmsRawOutstockDetail.outstockTime = DateTime.Now; + newWmsRawOutstockDetail.outstockWay = "2"; + newWmsRawOutstockDetail.createBy = "WCS"; + newWmsRawOutstockDetail.createDate = DateTime.Now; + newWmsRawOutstockDetail.stackAmount = 1; + + + dbContext.Add(newWmsRawOutstockDetail); + SystemData.UnLockOutLocation(wmsBaseLocation, dbContext); + dbContext.Remove(wmsRawStock); + wmsBaseLocation.locationStatus = "1"; + wmsBaseLocation.containerCode = null; + wmsBaseLocation.updateTime = DateTime.Now; + wmsBaseLocation.updateBy = "WCS"; + dbContext.Update(wmsBaseLocation); + dbContext.Update(wmsRawOutstock); + item.createTime = DateTime.Now; + item.nextPointId = floorLineEquip.objid; + item.nextPointNo = floorLineEquip.equipNo; + item.fromFloorNo = 3; + item.floorNo = 1; + item.taskStatus = 6; + dbContext.Update(item); + dbContext.WcsTaskLog.Where(t => t.objid == item.objid).Update(t => new WcsTaskLog { taskStatus = 6, updateTime = DateTime.Now }); + dbContext.SaveChanges(); + } + } + } + } + } + break; + } + } + catch (Exception ex) + { + if (ex is PlcException) + { + + } + else + { + _logger.Error(ex.Message + "\n" + ex.StackTrace); + } + } + finally + { + Thread.Sleep(1000); + } + } + } + } +} diff --git a/src/Khd.Core.Wcs/Wcs/ThirdFloorPoint.cs b/src/Khd.Core.Wcs/Wcs/ThirdFloorPoint.cs new file mode 100644 index 0000000..5f63d03 --- /dev/null +++ b/src/Khd.Core.Wcs/Wcs/ThirdFloorPoint.cs @@ -0,0 +1,312 @@ +using Khd.Core.Domain.Dto.TaskType; +using Khd.Core.Domain.Dto.waring; +using Khd.Core.Domain.Models; +using Khd.Core.EntityFramework; +using Khd.Core.Library; +using Khd.Core.Library.Mapper; +using Khd.Core.Plc.S7; +using Khd.Core.Wcs.Global; +using Masuit.Tools; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; +using System.Security.Cryptography; +using Z.EntityFramework.Plus; + +namespace Khd.Core.Wcs.Wcs +{ + /// + /// 三楼接驳位调度 + /// + public class ThirdFloorPoint + { + private readonly LoggerUtils _logger = new LoggerUtils(); + private readonly IHost _host; + private readonly BasePlcpoint LineRFID; + private readonly BasePlcpoint LineSignal; + int FloorNo { get; set; } + public ThirdFloorPoint(IHost host, int floor) + { + this._host = host; + FloorNo = floor; + this.LineRFID = StaticData.BasePlcpointList.First(t => t.plcpointNo == "RFID003"); + this.LineSignal = StaticData.BasePlcpointList.First(t => t.plcpointNo == "linesignal03"); + } + + + /// + /// 启动上件扫描监听 + /// + public void StartPoint() + { + + Thread FlowPointThread = new Thread(MonitorInLocatorPoint); + FlowPointThread.IsBackground = true; + FlowPointThread.Name = "ThirdFloorPoint"; + FlowPointThread.Start(); + Console.WriteLine(DateTime.Now + ":三楼接驳位调度启动成功"); + _logger.Info("三楼接驳位调度启动成功"); + } + + public void MonitorInLocatorPoint() + { + List ITypes = new List { 1, 3, 5, 7 }; + using var scope = _host.Services.CreateScope(); + using var dbContext = scope.ServiceProvider.GetRequiredService(); + List canNotIn = new List(); + while (true) + { + try + { + dbContext.ChangeTracker.Clear(); + //入库任务 + var rfid = StaticData.PlcDic[0].ReadRFID(LineRFID.plcpointAddress); + var isSignal = StaticData.PlcDic[0].Read(LineSignal.plcpointAddress); + if (rfid != null && isSignal != null) + { + + if (Convert.ToInt32(isSignal) == 1)//托盘到位 + { + BaseEquip baseEquip = StaticData.BaseEquip.First(t => t.floorNo == 3 && t.equipType == 1); + var wcsTask = dbContext.WcsTask.FirstOrDefault(t => t.nextPointId == baseEquip.objid); + var AgvEquip = StaticData.BaseEquip.First(t => t.floorNo == 3 && t.equipType == 4);//背负Agv + if (wcsTask != null)//如果不是null + { + + if (wcsTask.taskStatus == 5)//提升机任务是完成状态 + { + lock (SystemData.ThirdTaskLock) + { + MesBasePalletInfo? mesBasePalletInfo = dbContext.MesBasePalletInfo.Where(t => t.palletInfoCode == rfid).FirstOrDefault(); + if (mesBasePalletInfo != null) + { + MesBaseBarcodeInfo? mesBaseBarcodeInfo = dbContext.MesBaseBarcodeInfo.FirstOrDefault(t => t.barcodeInfo == mesBasePalletInfo.materialBarcode); + if (mesBaseBarcodeInfo != null) + { + // 目标库位 + WmsBaseLocation? wmsBaseLocation = null; + var wmsBaseLocations = dbContext.WmsBaseLocation + .Where(t => t.warehouseFloor == FloorNo) + .Where(t => t.activeFlag == "1") + .Where(t => t.delFlag == "0") + .Where(t => t.locationScrapType == "1") + .Where(t => t.locationStatus == "1") + .Where(t => t.warehouseId == 311) + .ToList();//所有未锁定的库位 + + //深库位有库存的库位 + List DeepContainerCodes = wmsBaseLocations + .Where(t => t.locDeep == 1) + .Where(t => !string.IsNullOrEmpty(t.containerCode)) + .Select(t => t.containerCode).ToList(); + + + + + //#region 弃用:改为优先把相同采购订单及批次号的放一块 优先找同销售订单的有库存的深库位对应的浅库位 + ////找相同型号及销售订单的深库位库存 + //List wmsRawStocks = dbContext.WmsRawStock.Where(t => t.materialId == mesBaseBarcodeInfo.materialId) + // .Where(t => t.saleOrderId == mesBaseBarcodeInfo.saleOrderId) + // .Where(t => DeepContainerCodes.Contains(t.palletInfoCode)) + // .Where(t => t.warehouseId == 311).ToList(); + //if (wmsRawStocks.Count > 0) + //{ + // //优先找同销售订单的有库存的深库位对应的浅库位 + // foreach (var wmsRawStock in wmsRawStocks) + // { + // // 深库位库存对用的Location信息 + // var deepStockLocation = wmsBaseLocations.Where(t => t.containerCode == wmsRawStock.palletInfoCode).First(); + // wmsBaseLocation = wmsBaseLocations.Where(t => string.IsNullOrEmpty(t.containerCode) && t.locationStatus == "1") + // .Where(t => t.locDeep == 2 && t.locColumn == deepStockLocation.locColumn) + // .Where(t => t.locRow == (deepStockLocation.locRow % 2 == 0 ? (deepStockLocation.locRow - 1) : (deepStockLocation.locRow + 1))) + // .FirstOrDefault(); + // if (wmsBaseLocation != null) + // { + // break; + // } + // } + //} + //#endregion + + + #region 优先找同采购订单及批次号的有库存的深库位对应的浅库位 + //找相同型号及采购订单及批次号的深库位库存 + List wmsRawStocks = (from stock in dbContext.WmsRawStock + join codeInfo in dbContext.MesBaseBarcodeInfo + on stock.instockBatch equals codeInfo.barcodeInfo + where codeInfo.batchCode == mesBaseBarcodeInfo.batchCode + && codeInfo.poNo== mesBaseBarcodeInfo.poNo && stock.materialId == mesBaseBarcodeInfo.materialId && stock.warehouseId == 311 + select stock).ToList(); + + + if (wmsRawStocks!=null && wmsRawStocks.Count > 0) + { + //优先找同销售订单的有库存的深库位对应的浅库位 + foreach (var wmsRawStock in wmsRawStocks) + { + // 深库位库存对用的Location信息 + var deepStockLocation = wmsBaseLocations.Where(t => t.containerCode == wmsRawStock.palletInfoCode).First(); + wmsBaseLocation = wmsBaseLocations.Where(t => string.IsNullOrEmpty(t.containerCode) && t.locationStatus == "1") + .Where(t => t.locDeep == 2 && t.locColumn == deepStockLocation.locColumn) + .Where(t => t.locRow == (deepStockLocation.locRow % 2 == 0 ? (deepStockLocation.locRow - 1) : (deepStockLocation.locRow + 1))) + .FirstOrDefault(); + if (wmsBaseLocation != null) + { + break; + } + } + } + #endregion + + + + + + if (wmsBaseLocation == null) + { // 在所有符合条件的库位里,找一个库位,优先深库位,但是如果是深库位,需要判断浅库位状态是否正常 + var searchLocations = wmsBaseLocations.Where(x => string.IsNullOrEmpty(x.containerCode) && x.locationStatus == "1").OrderBy(x => x.locDeep).ToList(); + foreach (var item in searchLocations) + { + if (item.locDeep == 1) + { + //浅库位能否使用 + var shallowLocation = wmsBaseLocations.Where(t => string.IsNullOrEmpty(t.containerCode) && t.locationStatus == "1") + .Where(t => t.locDeep == 2 && t.locColumn == item.locColumn) + .Where(t => t.locRow == (item.locRow % 2 == 0 ? (item.locRow - 1) : (item.locRow + 1))) + .FirstOrDefault(); + if (shallowLocation != null) + { + wmsBaseLocation = item; + break; + } + } + else + { + wmsBaseLocation = item; + break; + } + + } + } + + if (wmsBaseLocation != null) + { + dbContext.Remove(wcsTask); + WcsTask newTask = CoreMapper.Map(wcsTask); + newTask.objid = StaticData.SnowId.NextId(); + newTask.taskStatus = 0;//创建状态 + newTask.updateTime = DateTime.Now; + newTask.currPointId = baseEquip.objid; + newTask.currPointNo = baseEquip.equipNo; + newTask.nextPointId = AgvEquip.objid; + newTask.nextPointNo = AgvEquip.equipNo; + newTask.endPointId = wmsBaseLocation.locationId; + newTask.endPointNo = wmsBaseLocation.locationCode; + newTask.taskType = StaticTaskType.ThirdRawIn; + newTask.useFlag = 1; + wmsBaseLocation.locationStatus = "2"; + SystemData.LockOutLocation(wmsBaseLocation, dbContext); + dbContext.Update(wmsBaseLocation); + dbContext.Add(newTask); + WcsTaskLog wcsTaskLog = CoreMapper.Map(newTask); + dbContext.Add(wcsTaskLog); + dbContext.SaveChanges(); + canNotIn.Clear(); + SystemData.DeleteWaringLog(dbContext, WaringType.二楼入库任务创建失败); + Console.WriteLine(DateTime.Now + $":三楼接驳位调度入库任务,物料{mesBaseBarcodeInfo.materialId},托盘{rfid},库位{wmsBaseLocation.locationCode}"); + _logger.Info($"三楼接驳位调度入库任务,物料{mesBaseBarcodeInfo.materialId},托盘{rfid},库位{wmsBaseLocation.locationCode}"); + } + else + { + Console.WriteLine(DateTime.Now + ":三楼楼接驳位调度入库任务,未找到库位"); + _logger.Info("三楼接驳位调度入库任务,未找到库位"); + // TODO: 没有找到库位,添加报警处理 + SystemData.InsertWaringLog(dbContext, WaringType.二楼入库任务创建失败); + Thread.Sleep(1000 * 5); + + } + } + } + } + } + else if (wcsTask.taskStatus == 6)//小车任务是完成状态,说明是出库 + { + if (wcsTask.taskType == StaticTaskType.ThirdStockReturnTask) + { + if (string.IsNullOrEmpty(rfid)) + { + continue; + } + else if (wcsTask.containerNo == rfid) + { + BaseEquip nextEquip = StaticData.BaseEquip.First(t => t.equipType == 2);//提升机 + BaseEquip endEquip = StaticData.BaseEquip.First(t => t.objid == wcsTask.floorNo); + dbContext.Remove(wcsTask); + WcsTask newTask = CoreMapper.Map(wcsTask); + newTask.objid = StaticData.SnowId.NextId(); + newTask.nextPointId = nextEquip.objid; + newTask.nextPointNo = nextEquip.equipNo; + newTask.currPointId = baseEquip.objid; + newTask.currPointNo = baseEquip.equipNo; + newTask.fromFloorNo = FloorNo; + newTask.endPointId = endEquip.objid; + newTask.endPointNo = endEquip.equipNo; + newTask.taskStatus = 0; + newTask.ud1 = 10; + newTask.updateTime = DateTime.Now; + dbContext.Add(newTask); + WcsTaskLog wcsTaskLog = CoreMapper.Map(newTask); + dbContext.Add(wcsTaskLog); + dbContext.SaveChanges(); + } + } + else + { + BaseEquip nextEquip = StaticData.BaseEquip.First(t => t.equipType == 2);//提升机 + BaseEquip endEquip = StaticData.BaseEquip.First(t => t.objid == wcsTask.floorNo); + dbContext.Remove(wcsTask); + WcsTask newTask = CoreMapper.Map(wcsTask); + newTask.objid = StaticData.SnowId.NextId(); + newTask.containerNo = rfid; + newTask.nextPointId = nextEquip.objid; + newTask.nextPointNo = nextEquip.equipNo; + newTask.currPointId = baseEquip.objid; + newTask.currPointNo = baseEquip.equipNo; + newTask.fromFloorNo = FloorNo; + newTask.endPointId = endEquip.objid; + newTask.endPointNo = endEquip.equipNo; + newTask.taskStatus = 0; + newTask.ud1 = 10; + newTask.updateTime = DateTime.Now; + dbContext.Add(newTask); + WcsTaskLog wcsTaskLog = CoreMapper.Map(newTask); + dbContext.Add(wcsTaskLog); + dbContext.SaveChanges(); + } + } + } + } + else + { + SystemData.DeleteWaringLog(dbContext, WaringType.二楼入库任务创建失败); + } + } + } + catch (Exception ex) + { + if (ex is PlcException) + { + + } + else + { + _logger.Error(ex.Message + "\n" + ex.StackTrace); + } + } + finally + { + Thread.Sleep(1000); + } + } + } + } +} diff --git a/src/Khd.Core.Wcs/Wcs/UpLine.cs b/src/Khd.Core.Wcs/Wcs/UpLine.cs new file mode 100644 index 0000000..fc25186 --- /dev/null +++ b/src/Khd.Core.Wcs/Wcs/UpLine.cs @@ -0,0 +1,338 @@ +using Khd.Core.Domain.Dto.wcs; +using Khd.Core.Domain.Models; +using Khd.Core.EntityFramework; +using Khd.Core.Wcs.Global; +using Masuit.Tools.Logging; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Security.Policy; +using System.Text; +using System.Threading.Tasks; +using Thrift.Server; +using Thrift.Transport; +using ThriftService; +using static AngleSharp.Css.Values.CssRadialGradientValue; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Thrift.Protocol; +using System.Security.Cryptography.Xml; +using Z.EntityFramework.Plus; +using System.Net.NetworkInformation; + +namespace Khd.Core.Wcs.Wcs +{ + /// + /// 上件点线程 + /// + public class UpLine : WcsServer + { + private readonly IHost _host; + private readonly Plc.S7.Plc _plc; + List ScanPoint { get; set; }//点位信息 + BaseSitenode? sitenode { get; set; }//站台信息 + + NodeSetting? NodeSettingCarNo { get; set; } + NodeSetting? NodeSettingCarState { get; set; } + NodeSetting? NodeSettingCarRun { get; set; } + NodeSetting? NodeSettingWcsState { get; set; } + NodeSetting? NodeSettingWcsSend { get; set; } + NodeSetting? NodeSettingWcsSendMaterial { get; set; } + NodeSetting? NodeSettingPLCSendSendMaterialstate { get; set; } + public UpLine(IHost host, Plc.S7.Plc plc, string siteNo) + { + this._host = host; + this._plc = plc; + //this.ScanPoint = StaticData.NodeSettingList.Where(t => t.siteNo == siteNo).ToList();//加载当前站点所对应的点位 + this.sitenode = StaticData.SiteNodeList.FirstOrDefault(t => t.siteNo == siteNo);//获取当前站台信息 + this.NodeSettingCarNo = this.ScanPoint.FirstOrDefault(t => t.plcpointNo.Contains("carno")); + this.NodeSettingCarState = this.ScanPoint.FirstOrDefault(t => t.plcpointNo.Contains("carstate")); + this.NodeSettingCarRun = this.ScanPoint.FirstOrDefault(t => t.plcpointNo.Contains("carrun")); + this.NodeSettingWcsState = this.ScanPoint.FirstOrDefault(t => t.plcpointNo.Contains("plcsendK")); + this.NodeSettingWcsSend = this.ScanPoint.FirstOrDefault(t => t.plcpointNo.Contains("wcsend")); + this.NodeSettingWcsSendMaterial = this.ScanPoint.FirstOrDefault(t => t.plcpointNo.Contains("wcssendmessage")); + this.NodeSettingPLCSendSendMaterialstate = this.ScanPoint.FirstOrDefault(t => t.plcpointNo.Contains("plcsendmessage")); + try + { + //默认启动,清理plc的上位机写入点位值 + this._plc.Write(NodeSettingCarRun.plcpointAddress, MainCentralControl.QingKongDianWei); + this._plc.Write(NodeSettingWcsSend.plcpointAddress, MainCentralControl.QingKongDianWei); + this._plc.Write(NodeSettingWcsSendMaterial.plcpointAddress, MainCentralControl.QingKongDianWei); + } + catch (Exception ex) + { + Console.WriteLine("站点" + siteNo + " 初始化数据异常" + ex.Message); + LogManager.Error(ex); + } + } + + + /// + /// 启动线程 + /// + public void StartPoint() + { + Thread TestThread1 = new Thread(new ParameterizedThreadStart(StartScanThrift)); + TestThread1.IsBackground = true; + TestThread1.Start(this.sitenode); + Thread TestThread2 = new Thread(new ParameterizedThreadStart(StartSendCarThrift)); + TestThread2.IsBackground = true; + TestThread2.Start(this.sitenode); + Thread TestThread3 = new Thread(ClearSendCar); + TestThread3.IsBackground = true; + TestThread3.Start(); + } + /// + /// 启动推送车辆到位队列 + /// + private void StartScanThrift(object NodeSettingModel) + { + var sitenodemodel = NodeSettingModel as BaseSitenode; + int TSpoint = Convert.ToInt32(sitenodemodel.thriftPort); + string IpAddress = sitenodemodel.siteIpaddress; + TTransport transport = new TSocket(IpAddress, TSpoint); + while (true) + { + try + { + //启动thrift 推送服务 + //推送车辆到位情况 + transport.Open(); + TProtocol protocol = new TBinaryProtocol(transport); + WcsThrift.Client client = new WcsThrift.Client(protocol); + client.hello(ReceiveCarNo("")); + } + catch (Exception ex) + { + LogManager.Info($"wcs上件控制类推送车辆到位信息Thrift方法报错 >>> {ex.Message}"); + } + finally + { + transport.Close(); + Thread.Sleep(1000); + } + } + } + + /// + /// 启动小车扫描监听队列 + /// + private void StartSendCarThrift(object NodeSettingModel) + { + SendCar(null, null, null); + var sitenodemodel = NodeSettingModel as BaseSitenode; + int JSport = Convert.ToInt32(sitenodemodel.siteServerport); + while (true) + { + try + { + //启动thrift接收服务 + //接收挂具与Vin物料信息,上件绑定信息 + WcsServer wcsServer = new WcsServer(); + wcsServer.SendCarEvent += SendCar; + WcsThrift.Processor processor = new WcsThrift.Processor(wcsServer); + TServerTransport serverTransport = new TServerSocket(JSport); + TServer server = new TSimpleServer(processor, serverTransport); + Console.WriteLine($"站点:{this.sitenode.siteNo},当前时间:{DateTime.Now},接收客户端发车方法启动.. "); + server.Serve(); + } + catch (Exception ex) + { + LogManager.Info($"wcs上件控制类控制发车Thrift方法报错 >>> {ex.Message}"); + } + finally + { + Thread.Sleep(1000); + } + } + } + + /// + /// 发车 + /// + /// + /// + /// + /// + public string SendCar(List carlist, string order_code, string amount) + { + #region 测试屏蔽 + //Console.WriteLine($"服务端发车触发 >>> carlist[0]:{carlist.FirstOrDefault()},vin条码:{order_code},车辆长度:{amount}"); + //return "11"; + #endregion + //通用逻辑:(1 是否空车 2 物料号 3 上件数量) + // 通用逻辑下,下一站点固定(配置) + // -判断小车是否到位,小车已下发去向,清空下发数据信息 + // - 判断 小车是否到位,小车未下发去向 + // - 进库区判断: 库存是否满; + // -特殊逻辑:下一站点多个站点,按多条线缓存数优先进少的;按物料 + 属性区分进哪个站点,可配置 + try + { + var carno = this._plc.Read(NodeSettingCarNo.plcpointAddress); + var carstate = this._plc.Read(NodeSettingCarState.plcpointAddress); + var carrun = this._plc.Read(NodeSettingCarRun.plcpointAddress); + var wcsstate = this._plc.Read(NodeSettingWcsState.plcpointAddress); + var wcsend = this._plc.Read(NodeSettingWcsSend.plcpointAddress); + if (carno != null && carstate != null && carrun != null && wcsstate != null && wcsend != null) + { + //正常读到小车信息 + if (Convert.ToInt32(carno) > 0 && Convert.ToInt32(wcsend) == 0 && Convert.ToInt32(wcsstate) == 0 && Convert.ToInt32(carstate) == 1 && Convert.ToInt32(carrun) == 0) + { + //根据上件点,物料号,获取下一点位信息 + var TargetTo = GetTargetTo(Convert.ToInt32(carno), order_code, this.sitenode.siteNo); + //业务处理 + if (string.IsNullOrWhiteSpace(TargetTo) || string.IsNullOrWhiteSpace(order_code)) + { + //if (string.IsNullOrWhiteSpace(TargetTo)) LogManager.Info($"错误日志输出 >>> 站点:{this.sitenode.siteNo},挂具:{carno}上件车辆去向有误!"); + //if (string.IsNullOrWhiteSpace(order_code)) LogManager.Info($"错误日志输出 >>> 站点:{this.sitenode.siteNo},挂具:{carno}Thrift传输Vin码为空!"); + Thread.Sleep(1000); + return null; + } + //写入PLC + var ToInt16QuXiang = MainCentralControl.getValue("2", TargetTo); + var ToInt16ChangDu = MainCentralControl.getValue("2", amount); + this._plc.Write(this.NodeSettingCarRun.plcpointAddress, ToInt16QuXiang);//写入小车去向 + this._plc.Write(this.NodeSettingWcsSend.plcpointAddress, MainCentralControl.WcsChuLiWanCheng);//写入wms处理完成 + this._plc.Write(this.NodeSettingWcsSendMaterial.plcpointAddress, ToInt16ChangDu);//写入车身长度 + LogManager.Info($"当前时间 :{DateTime.Now} >>> 上件站点 :{this.sitenode.siteNo}发车 ,挂具号:{carno},去向:{ToInt16QuXiang},Wcs处理完成:{MainCentralControl.WcsChuLiWanCheng},vin条码:{order_code},车身长度:{ToInt16ChangDu}"); + return "1";//发车成功反馈 + } + } + } + catch (Exception ex) + { + LogManager.Error(ex); + } + finally + { + Thread.Sleep(1000); + } + return null; + } + //根据上件点,物料号,获取下一点位信息 + public string GetTargetTo(int carno, string materialNo, string sideno) + { + try + { + if (string.IsNullOrWhiteSpace(materialNo) || string.IsNullOrWhiteSpace(sideno)) + { + return null; + } + using var scope = _host.Services.CreateScope(); + using var dbContext = scope.ServiceProvider.GetRequiredService(); + //1 读出点位信息,下一站点 + + //2 根据物料查下一站点 + + var WaitdownlineModel = dbContext.BaseWaitdownline.Where(t => t.carNo == carno).FirstOrDefault(); + var basecarModel = dbContext.BaseCar.Where(t => t.carNo == carno).FirstOrDefault(); + var orderModel = dbContext.BaseProductionOrderSplit.Where(t => t.orderCode == materialNo).FirstOrDefault(); + if (WaitdownlineModel == null && basecarModel != null && orderModel != null)//Waitdownline不存在当前车辆信息 + { + //添加挂具与物料绑定信息 + BaseWaitdownline waitdownModel = new() + { + id = Guid.NewGuid(), + carId = basecarModel.id, + carNo = basecarModel.carNo, + carName = basecarModel.carName, + downline = 1, + materielNo = materialNo, + materielNum = 1, + isDelete = 0, + createTime = DateTime.Now, + createBy = sideno, + definefield1 = orderModel.lineCode + }; + dbContext.Add(waitdownModel); + dbContext.SaveChanges(); + } + else//Waitdownline存在当前车辆信息即改 + { + //base_waitdownline表中挂具与任务VIN码绑定,修改车辆线上状态为已上线 + dbContext.BaseWaitdownline.Where(t => t.carNo == carno).Update(a => new BaseWaitdownline() { materielNo = materialNo, materielNum = 1, downline = 1, createBy = sideno, createTime = DateTime.Now, isDelete = 0, definefield1 = orderModel.lineCode }); + } + return "1"; + } + catch (Exception ex) + { + LogManager.Info($"UpLine类GetTargetTo方法报错 >>> {ex.Message}"); + return null; + } + + } + /// + /// 返回给客户端车辆到位及车辆信息 + /// + /// 无用参数 + /// + public string ReceiveCarNo(string name) + { + + try + { + var carno = this._plc.Read(NodeSettingCarNo.plcpointAddress); + var carstate = this._plc.Read(NodeSettingCarState.plcpointAddress); + var carrun = this._plc.Read(NodeSettingCarRun.plcpointAddress); + var wcsstate = this._plc.Read(NodeSettingWcsState.plcpointAddress); + var wcsend = this._plc.Read(NodeSettingWcsSend.plcpointAddress); + if (carno != null && carstate != null && carrun != null && wcsstate != null && wcsend != null) + { + if (Convert.ToInt32(carno) > 0 && Convert.ToInt32(wcsend) == 1 && Convert.ToInt32(wcsstate) == 1) + { + return ""; + } + //正常读到小车信息 + if (Convert.ToInt32(carno) > 0 && Convert.ToInt32(wcsend) == 0 && Convert.ToInt32(wcsstate) == 0 && Convert.ToInt32(carstate) == 1 && Convert.ToInt32(carrun) == 0) + { + string TuiSongCarNo = carno.ToString(); + return TuiSongCarNo; + } + } + Thread.Sleep(1000); + return ""; + } + catch (Exception ex) + { + LogManager.Info($""); + return ""; + } + } + /// + /// 启动小车发出后清空预设点位线程 + /// + private void ClearSendCar() + { + while (true) + { + try + { + var carno = this._plc.Read(NodeSettingCarNo.plcpointAddress); + var carstate = this._plc.Read(NodeSettingCarState.plcpointAddress); + var carrun = this._plc.Read(NodeSettingCarRun.plcpointAddress); + var wcsstate = this._plc.Read(NodeSettingWcsState.plcpointAddress); + var wcsend = this._plc.Read(NodeSettingWcsSend.plcpointAddress); + //清除点位信息 + if (Convert.ToInt32(carno) == 0 && Convert.ToInt32(wcsend) == 1 && Convert.ToInt32(wcsstate) == 1) + { + this._plc.Write(NodeSettingCarRun.plcpointAddress, MainCentralControl.QingKongDianWei); + this._plc.Write(NodeSettingWcsSend.plcpointAddress, MainCentralControl.QingKongDianWei); + this._plc.Write(NodeSettingWcsSendMaterial.plcpointAddress, MainCentralControl.QingKongDianWei); + } + } + catch (Exception ex) + { + LogManager.Info($"发车后清空点位线程报错 >>> {ex.Message}"); + } + finally + { + Thread.Sleep(1000); + } + } + } + } +} diff --git a/src/Khd.Core.Wcs/update.cs b/src/Khd.Core.Wcs/update.cs new file mode 100644 index 0000000..00c1c0b --- /dev/null +++ b/src/Khd.Core.Wcs/update.cs @@ -0,0 +1,189 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.IO; +using System.Net.Http; +using HtmlAgilityPack; +using System.Linq; +using System.Diagnostics; +class Update +{ + public void Update1() + { + string iisServerBaseUrl = "http://192.168.202.23:8080/"; // IIS服务器基本URL + string iisFolder = ""; // IIS服务器上的文件夹路径 + string localFolderBase = @"D:\"; // 本地文件夹的基本路径 + string localFolder = FindLocalFolder(localFolderBase); + SynchronizeFiles(iisServerBaseUrl, iisFolder, localFolder); + + // 继续运行应用程序的主要逻辑 + Console.WriteLine("应用程序启动..."); + // 在这里添加你的应用程序的主要逻辑 + + Console.ReadLine(); + } + + public string FindLocalFolder(string localFolderBase) + { + for (int i = 1; i <= 8; i++) + { + string localFolder = Path.Combine(localFolderBase, $"C{i}"); + + if (Directory.Exists(localFolder)) + { + return localFolder; + } + } + + return null; + } + + public void SynchronizeFiles(string serverBaseUrl, string serverFolder, string localFolder) + { + using (HttpClient client = new HttpClient()) + { + try + { + HttpResponseMessage response = client.GetAsync(new Uri(serverBaseUrl + serverFolder)).Result; + response.EnsureSuccessStatusCode(); + + string responseContent = response.Content.ReadAsStringAsync().Result; + + // 使用HtmlAgilityPack解析HTML内容 + HtmlDocument doc = new HtmlDocument(); + doc.LoadHtml(responseContent); + + // 查找所有包含文件名和文件夹名的标签 + var links = doc.DocumentNode.SelectNodes("//a"); + + if (links != null) + { + foreach (var link in links) + { + string itemName = link.InnerText; + string itemUrl = serverBaseUrl + serverFolder + itemName; + string localPath = Path.Combine(localFolder, itemName); + + if (link.InnerText.StartsWith("")) + { + // 这是一个文件夹 + if (!Directory.Exists(localPath)) + { + Directory.CreateDirectory(localPath); + } + + // 递归处理文件夹中的内容 + SynchronizeFiles(serverBaseUrl, serverFolder + itemName + "/", localPath); + } + else + { + // 这是一个文件 + if (!string.Equals(itemName, "web.config", StringComparison.OrdinalIgnoreCase)) + { + // 检查文件类型是否需要更新 + string fileExtension = Path.GetExtension(itemName).ToLower(); + if (ShouldUpdateFile(fileExtension)) + { + if (File.Exists(localPath)) + { + bool filesAreEqual = AreFilesEqual(itemUrl, localPath); + + if (!filesAreEqual) + { + DownloadFile(itemUrl, localPath); + Console.WriteLine($"已下载并覆盖文件: {itemName}"); + } + else + { + Console.WriteLine($"该文件为最新版本: {itemName}!!!"); + } + } + else + { + DownloadFile(itemUrl, localPath); + Console.WriteLine($"已下载文件: {itemName}"); + } + } + else + { + Console.WriteLine($"不需要更新的文件类型: {fileExtension}"); + } + } + } + } + // 在配置文件更新后,执行以下代码重启程序 + Process.Start("Up.bat"); + } + else + { + Console.WriteLine("未找到文件列表"); + } + } + catch (HttpRequestException ex) + { + Console.WriteLine($"HTTP请求失败: {ex.Message}"); + } + catch (Exception ex) + { + Console.WriteLine($"发生错误: {ex.Message}"); + } + } + } + + public bool ShouldUpdateFile(string fileExtension) + { + // 添加需要更新的文件类型 + string[] allowedExtensions = { ".exe", ".dll", ".json", ".xml" }; + + // 如果文件类型在允许更新的文件类型列表中,则返回 true,否则返回 false + return allowedExtensions.Contains(fileExtension); + } + + + + + public void DownloadFile(string fileUrl, string localFilePath) + { + using (HttpClient client = new HttpClient()) + { + try + { + HttpResponseMessage response = client.GetAsync(new Uri(fileUrl)).Result; + response.EnsureSuccessStatusCode(); + + using (Stream contentStream = response.Content.ReadAsStreamAsync().Result) + { + using (Stream fileStream = File.Create(localFilePath)) + { + contentStream.CopyTo(fileStream); + } + } + + Console.WriteLine($"已成功下载文件: {localFilePath}"); + } + catch (HttpRequestException ex) + { + // 处理连接断开或其他HTTP请求错误 + Console.WriteLine($"HTTP请求失败: {ex.Message}"); + // 在这里可以添加重试逻辑或其他处理方式 + } + catch (Exception ex) + { + Console.WriteLine($"发生错误: {ex.Message}"); + } + } + } + + + public bool AreFilesEqual(string file1Url, string file2Path) + { + byte[] file1Content = File.ReadAllBytes(file2Path); + + using (HttpClient client = new HttpClient()) + { + byte[] file2Content = client.GetByteArrayAsync(file1Url).Result; + + return StructuralComparisons.StructuralEqualityComparer.Equals(file1Content, file2Content); + } + } +} diff --git a/src/Khd.Core.Wpf/App.xaml b/src/Khd.Core.Wpf/App.xaml new file mode 100644 index 0000000..9611e71 --- /dev/null +++ b/src/Khd.Core.Wpf/App.xaml @@ -0,0 +1,14 @@ + + + + + + + + + + diff --git a/src/Khd.Core.Wpf/App.xaml.cs b/src/Khd.Core.Wpf/App.xaml.cs new file mode 100644 index 0000000..0ad4d13 --- /dev/null +++ b/src/Khd.Core.Wpf/App.xaml.cs @@ -0,0 +1,122 @@ +using Microsoft.Extensions.Configuration; +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.IO; +using System.Threading.Tasks; +using System.Windows; +namespace Khd.Core.Wpf +{ + /// + /// Interaction logic for App.xaml + /// + public partial class App : Application + { + public App() + { + + //UI线程未捕获异常处理事件(UI主线程) + this.DispatcherUnhandledException += App_DispatcherUnhandledException; + + //非UI线程未捕获异常处理事件(例如自己创建的一个子线程) + AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException; + //Task线程内未捕获异常处理事件 + TaskScheduler.UnobservedTaskException += TaskScheduler_UnobservedTaskException;//Task异常 + + IConfigurationRoot configuration = new ConfigurationBuilder() + .SetBasePath(AppDomain.CurrentDomain.BaseDirectory) + .AddJsonFile("appsettings.json") + .Build(); + + SystemData.PlcConfigs = configuration.GetSection("PlcConfigs").Get>(); + ConnectionStrings.ConnectionString = configuration["ConnectionStrings:DefaultConnection"].ToString(); + SystemData.MenuList = configuration.GetSection("MenuList").Get>(); + try + { + SystemData.NeedLogin = bool.Parse(File.ReadAllText("Login.txt")); + } + catch + { + + } + LoadVersionMsg(); + ////配置文件 加载 Thrift 推送端口 + //ThriftConfig.ThriftIpAddress = configuration["ThriftConfig:ThriftIpAddress"].ToString(); + //ThriftConfig.JiesShouDuanKou = int.Parse(configuration["ThriftConfig:JiesShouDuanKou"]); + //ThriftConfig.TuiSongDuankou = int.Parse(configuration["ThriftConfig:TuiSongDuankou"]); + //ThriftConfig.UpSite = configuration["ThriftConfig:upsite"].ToString(); + //FlagConfig.UpFlagNum = int.Parse(configuration["FlagConfig:UpFlagNum"]); + } + void App_DispatcherUnhandledException(object sender, System.Windows.Threading.DispatcherUnhandledExceptionEventArgs e) + { + try + { + HandleException(e.Exception); + } + catch (Exception ex) + { + HandleException(ex); + } + finally + { + e.Handled = true; + } + } + private static void HandleException(Exception ex) + { + //Logger log = new Logger(); + //log.Log(ex.ToString()); + } + //非UI线程未捕获异常处理事件(例如自己创建的一个子线程) + private static void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e) + { + try + { + var exception = e.ExceptionObject as Exception; + if (exception != null) + { + HandleException(exception); + } + } + catch (Exception ex) + { + HandleException(ex); + } + finally + { + //ignore + } + } + private static void TaskScheduler_UnobservedTaskException(object sender, UnobservedTaskExceptionEventArgs e) + { + try + { + var exception = e.Exception as Exception; + if (exception != null) + { + HandleException(exception); + } + } + catch (Exception ex) + { + HandleException(ex); + } + finally + { + e.SetObserved(); + } + } + private static void LoadVersionMsg() + { + try + { + SystemData.ProcessName = Process.GetCurrentProcess().ProcessName; + SystemData.VerSion = File.ReadAllText("Version.txt"); + } + catch + { + + } + } + } +} diff --git a/src/Khd.Core.Wpf/AssemblyInfo.cs b/src/Khd.Core.Wpf/AssemblyInfo.cs new file mode 100644 index 0000000..8b5504e --- /dev/null +++ b/src/Khd.Core.Wpf/AssemblyInfo.cs @@ -0,0 +1,10 @@ +using System.Windows; + +[assembly: ThemeInfo( + ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located + //(used if a resource is not found in the page, + // or application resource dictionaries) + ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located + //(used if a resource is not found in the page, + // app, or any theme specific resource dictionaries) +)] diff --git a/src/Khd.Core.Wpf/CSS/DataGridClass.xaml b/src/Khd.Core.Wpf/CSS/DataGridClass.xaml new file mode 100644 index 0000000..f00d059 --- /dev/null +++ b/src/Khd.Core.Wpf/CSS/DataGridClass.xaml @@ -0,0 +1,99 @@ + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/Khd.Core.Wpf/CSS/NormalSmlBtnClass.xaml b/src/Khd.Core.Wpf/CSS/NormalSmlBtnClass.xaml new file mode 100644 index 0000000..3cefa1e --- /dev/null +++ b/src/Khd.Core.Wpf/CSS/NormalSmlBtnClass.xaml @@ -0,0 +1,13 @@ + + + + + + \ No newline at end of file diff --git a/src/Khd.Core.Wpf/CSS/PageControl.xaml b/src/Khd.Core.Wpf/CSS/PageControl.xaml new file mode 100644 index 0000000..7916800 --- /dev/null +++ b/src/Khd.Core.Wpf/CSS/PageControl.xaml @@ -0,0 +1,27 @@ + + + + + + + + + + + + + + + diff --git a/src/Khd.Core.Wpf/Form/CheShenChangDuGuanLi.xaml.cs b/src/Khd.Core.Wpf/Form/CheShenChangDuGuanLi.xaml.cs new file mode 100644 index 0000000..03b0d97 --- /dev/null +++ b/src/Khd.Core.Wpf/Form/CheShenChangDuGuanLi.xaml.cs @@ -0,0 +1,92 @@ +using HandyControl.Tools.Extension; +using Masuit.Tools.Logging; +using Microsoft.Extensions.Hosting; +using System; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Input; + +namespace Khd.Core.Wpf.Form +{ + /// + /// CheShenChangDuGuanLi.xaml 的交互逻辑 + /// + public partial class CheShenChangDuGuanLi : Window + { + private readonly IHost _host; + public CheShenChangDuGuanLi(IHost host) + { + InitializeComponent(); + this._host = host; + } + /// + /// 页面加载方法 + /// + /// + /// + private void Window_Loaded(object sender, RoutedEventArgs e) + { + try + { + + } + catch (Exception ex) + { + LogManager.Info($"窗体加载事件报错 >>> {ex.Message}"); + } + } + /// + /// 显示序号事件 + /// + /// + /// + private void dgData_LoadingRow(object sender, DataGridRowEventArgs e) + { e.Row.Header = e.Row.GetIndex() + 1; } + + private void DataGrid_KeyDown(object sender, KeyEventArgs e) + { + try + { + if (e.Key == Key.Enter) + { + // Move focus away from the DataGrid to exit edit mode + Keyboard.ClearFocus(); + dgData_LoadingRow(null, null); + Window_Loaded(null, null); + } + } + catch (Exception) + { + } + + } + + private void cloce_Click(object sender, RoutedEventArgs e) + { + this.Close(); + } + /// + /// 保存按钮保存数据 + /// + /// + /// + private void inster_Click(object sender, RoutedEventArgs e) + { + try + { + if (!marterCode.Text.IsNullOrEmpty() && !marterName.Text.IsNullOrEmpty() && marterType.SelectedIndex != -1) + { + + } + else + { + MessageBox.Show("请输入完整数据!!!"); + } + } + catch (Exception ex) + { + MessageBox.Show($"数据添加报错 >>> {ex.Message}", "操作失败提示!"); + } + } + } +} diff --git a/src/Khd.Core.Wpf/Form/FormBoard.xaml b/src/Khd.Core.Wpf/Form/FormBoard.xaml new file mode 100644 index 0000000..1bf068c --- /dev/null +++ b/src/Khd.Core.Wpf/Form/FormBoard.xaml @@ -0,0 +1,1141 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Khd.Core.Wpf/Form/FormBoard.xaml.cs b/src/Khd.Core.Wpf/Form/FormBoard.xaml.cs new file mode 100644 index 0000000..d810190 --- /dev/null +++ b/src/Khd.Core.Wpf/Form/FormBoard.xaml.cs @@ -0,0 +1,1392 @@ + +using Khd.Core.Domain.Models; +using Khd.Core.EntityFramework; +using Masuit.Tools.Logging; +using Microsoft.EntityFrameworkCore; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; +using Microsoft.Win32; +using OfficeOpenXml; +using System; +using System.Collections.Generic; +using System.Data; +using System.IO; +using System.Linq; +using System.Text.RegularExpressions; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Input; +using System.Windows.Media; +using System.Windows.Media.Imaging; +using System.Windows.Threading; +using Thrift.Protocol; +using Thrift.Transport; + +namespace Khd.Core.Wpf.Form +{ + /// + /// FormBoard.xaml 的交互逻辑 + /// + public partial class FormBoard : Window + { + private readonly IHost _host; + private Khd.Core.Plc.S7.Plc _plc; + private DispatcherTimer ShowTimer;//刷新时间 + private DispatcherTimer PLCMessage;//呈现PLC机柜信息 + private DispatcherTimer ShowOrderMessage;//呈现PLC机柜信息 + private object order_code; + private int UpState;//对应上件站点的状态,0为良好 1为损坏 + //FormShowSelect formSelect; + // public static int WeekNo = CommonHelper.WeekOfYear(DateTime.Now, new System.Globalization.CultureInfo("zh-CN")); + + /// + /// 构造方法 + /// + public FormBoard(IHost host) + { + InitializeComponent(); + this._host = host; + } + /// + /// 页面加载事件 + /// + /// + /// + private void FormBoard_Loaded(object sender, RoutedEventArgs e) + { + try + { + LogManager.Info($"--------------------------当前时间 :{DateTime.Now} >>> 客户端启动;"); + //设置显示任务栏 + if (WindowState == WindowState.Normal) + { + MaxHeight = SystemParameters.MaximizedPrimaryScreenHeight; + WindowState = WindowState.Maximized; + } + //加载dategrid信息 + LoadMaterial_GetMessage(""); + ////连接PLC判断 + //var plc = new Khd.Core.Plc.S7.Plc((CpuType)PlcConfig.CpuType, PlcConfig.IP, PlcConfig.Port, + //PlcConfig.Rack, PlcConfig.Slot); + //// plc.Open(); + //if (!plc.IsConnected) + //{ + // MessageBox.Show("PLC连接失败,重新连接"); + //} + //else + //{ + // this._plc = plc; + //} + + //ShowTimer = new System.Windows.Threading.DispatcherTimer(); + //ShowTimer.Tick += new EventHandler(ShowCurTimer);//起个Timer一直获取当前时间 + //ShowTimer.Interval = new TimeSpan(0, 0, 0, 1, 0); + //ShowTimer.Start(); + + //#region 测试client,调用wcs服务端 + + ////TTransport transport = new TSocket("localhost", 9091); + ////transport.Open(); + ////TProtocol protocol = new TBinaryProtocol(transport); + ////WcsThrift.Client client = new WcsThrift.Client(protocol); + ////client.hello("Sunzy"); + + //#endregion + + ////启动Thriftserver + //Thread ThriftThread = new Thread(StartThriftServer);//接收服务端的推送信息 + //ThriftThread.IsBackground = true; + //ThriftThread.Start(); + + //PLCMessage = new DispatcherTimer(); + //PLCMessage.Tick += new EventHandler(PLCmessage); //委托获取点位方法 + //PLCMessage.Interval = new TimeSpan(0, 0, 0, 0, 300); + //PLCMessage.Start(); + + ////string result = ThriftConfig.UpSite == "k46" ? " K46" : " K48"; + ////this.lab_Title.Content = (string)this.lab_Title.Content + result; + + ////载具到位状态 + //this.labzjydw.Visibility = System.Windows.Visibility.Hidden; + //this.imgzjydw.Visibility = System.Windows.Visibility.Hidden; + //this.labzjwdw.Visibility = System.Windows.Visibility.Visible; + //this.imgzjwdw.Visibility = System.Windows.Visibility.Visible; + + //if (ThriftConfig.UpSite == "k48") + //{ + // this.spl_sunhuaizhakoumianban.Visibility = System.Windows.Visibility.Visible; + // using var scope = _host.Services.CreateScope(); + // using var dbContext = scope.ServiceProvider.GetRequiredService(); + // var getFlagState = dbContext.BaseAmima.Where(t => t.name == "UpState").FirstOrDefault(); + // if (getFlagState != null) + // { + // int zhuangtai = getFlagState.password == "2" ? 2 : 1; + // string quxiang = getFlagState.direction == 1 ? "直通" : "弯通"; + // if (zhuangtai == 2) + // { + // this.lab_shangjiandianzhuangtai.Content = "上件点正常!K22按照任务线别方向流转."; + // this.lab_shangjiandianzhuangtai.Foreground = new SolidColorBrush(Colors.Green); + // this.spl_sunhuaizhakouquxiang.Visibility = System.Windows.Visibility.Hidden; + // } + // else + // { + // this.lab_shangjiandianzhuangtai.Content = $"上件点损坏!人工维护去向:{quxiang}"; + // this.lab_shangjiandianzhuangtai.Foreground = new SolidColorBrush(Colors.Red); + // this.spl_sunhuaizhakouquxiang.Visibility = System.Windows.Visibility.Visible; + // } + // } + //} + //else + //{ + // this.spl_sunhuaizhakoumianban.Visibility = System.Windows.Visibility.Hidden; + //} + + } + catch (Exception ex) + { + MessageBox.Show(ex.Message); + } + + } + public void StartThriftServer() + { + try + { + //int point = Convert.ToInt32(ThriftConfig.JiesShouDuanKou); + //WcsServer wcsServer = new WcsServer(); + ////wcsServer.SendCarEvent += SendCar; + //wcsServer.helloEvent += hello; + //WcsThrift.Processor processor = new WcsThrift.Processor(wcsServer); + //TServerTransport serverTransport = new TServerSocket(point); + //TServer server = new TSimpleServer(processor, serverTransport); + //server.Serve(); + } + catch (Exception ex) + { + Application.Current.Dispatcher.Invoke(new Action( + delegate + { + //设置图片为未到位 + this.CarNo.Text = "Null"; + this.labzjydw.Visibility = System.Windows.Visibility.Hidden; + this.imgzjydw.Visibility = System.Windows.Visibility.Hidden; + this.labzjwdw.Visibility = System.Windows.Visibility.Visible; + this.imgzjwdw.Visibility = System.Windows.Visibility.Visible; + })); + LogManager.Error(ex); + } + + } + public string hello(string name) + { + //Console.WriteLine($"hello {name}"); + //return $"ServerResponse receive from client name:{name}"; + try + { + if (!string.IsNullOrWhiteSpace(name)) + { + Application.Current.Dispatcher.Invoke(new Action( + delegate + { + //设置图片为已到位、显示挂具号 + this.CarNo.Text = name; + this.labzjydw.Visibility = System.Windows.Visibility.Visible; + this.imgzjydw.Visibility = System.Windows.Visibility.Visible; + this.labzjwdw.Visibility = System.Windows.Visibility.Hidden; + this.imgzjwdw.Visibility = System.Windows.Visibility.Hidden; + })); + } + else + { + Application.Current.Dispatcher.Invoke(new Action( + delegate + { + //设置图片为未到位 + //this.CarNo.Clear(); + this.labzjydw.Visibility = System.Windows.Visibility.Hidden; + this.imgzjydw.Visibility = System.Windows.Visibility.Hidden; + this.labzjwdw.Visibility = System.Windows.Visibility.Visible; + this.imgzjwdw.Visibility = System.Windows.Visibility.Visible; + })); + } + } + catch (Exception ex) + { + LogManager.Info($"客户端接收服务端推送的小车信息方法报错 >>> {ex.Message}"); + } + return ""; + } + + /// + /// 发车方法 + /// + /// + /// Vin条码号 + public void SendCar(List carlist, string order_code) + { + TTransport transport = new TSocket(ThriftConfig.ThriftIpAddress, ThriftConfig.TuiSongDuankou); + try + { + //Console.WriteLine($"hello carlist[0]:{carlist.FirstOrDefault()}|order_code:{order_code}|amount:{amount}"); + //return $"ServerResponse receive from client order_code:{order_code}"; + transport.Open(); + TProtocol protocol = new TBinaryProtocol(transport); + WcsThrift.Client client = new WcsThrift.Client(protocol); + //var ret = client.SendCar(carlist, order_code, order_code); + //if (ret == "1")//与服务端交互成功发车时 + //{ + // Application.Current.Dispatcher.Invoke(new Action( + // delegate + // { + // //发车成功提示反馈 + // this.lba_ThrifTtitle.Foreground = new SolidColorBrush(Colors.Green); + // this.lba_ThrifTtitle.Content = "发车成功!"; + // //设置为未到位 + // this.labzjwdw.Visibility = System.Windows.Visibility.Visible; + // this.imgzjwdw.Visibility = System.Windows.Visibility.Visible; + // this.labzjydw.Visibility = System.Windows.Visibility.Hidden; + // this.imgzjydw.Visibility = System.Windows.Visibility.Hidden; + // })); + //} + //else//与服务端交互失败时 + //{ + + // Application.Current.Dispatcher.Invoke(new Action( + // delegate + // { + // this.lba_ThrifTtitle.Foreground = new SolidColorBrush(Colors.Red); + // this.lba_ThrifTtitle.Content = $"Thrift交互失败!"; + // //发车失败依然显示到位 + // this.labzjwdw.Visibility = System.Windows.Visibility.Hidden; + // this.imgzjwdw.Visibility = System.Windows.Visibility.Hidden; + // this.labzjydw.Visibility = System.Windows.Visibility.Visible; + // this.imgzjydw.Visibility = System.Windows.Visibility.Visible; + // })); + //} + } + catch (Exception ex) + { + LogManager.Info($"发车方法报错 >>> {ex.Message}"); + } + finally + { + transport.Close(); + transport.Dispose(); + } + } + /// + /// 显示序号事件 + /// + /// + /// + private void dgData_LoadingRow(object sender, DataGridRowEventArgs e) + { e.Row.Header = e.Row.GetIndex() + 1; } + /// + /// 显示日期事件timer + /// + /// + /// + public void ShowCurTimer(object sender, EventArgs e) + { + try + { + LabDate.Content = DateTime.Now.ToString("yyyy年MM月dd日"); + LabTime.Content = DateTime.Now.ToString("HH:mm:ss"); + } + catch (Exception) + { + } + } + /// + /// 点击退出按钮 + /// + /// + /// + private void btnExit_Click(object sender, RoutedEventArgs e) + { + //if (MessageBox.Show("是否确认关闭程序", "提示信息", MessageBoxButton.YesNo, MessageBoxImage.Information) == MessageBoxResult.No) + //{ + + //} + //else + //{ + // System.Environment.Exit(System.Environment.ExitCode); + //} + if (MessageBox.Show("是否确认关闭程序", "提示信息", MessageBoxButton.YesNo, MessageBoxImage.Information) == MessageBoxResult.Yes) + { + System.Environment.Exit(System.Environment.ExitCode); + } + } + private void Close(object sender, EventArgs e) + { + System.Environment.Exit(System.Environment.ExitCode); + } + /// + /// dgData_LoadingRow 序号列表 + /// + /// + /// + private void dgData_LoadingRow1(object sender, DataGridRowEventArgs e) + { + e.Row.Header = e.Row.GetIndex() + 1; + dynamic item = e.Row.Item; + if (item != null) + { + if (order_code != null) + { + if (item.order_code.Equals(order_code)) + { + e.Row.Background = new SolidColorBrush(Colors.Green); + } + } + } + } + /// + /// 上件操作按钮点击事件 + /// + /// + /// + private void BtnUpMenu_Click(object sender, RoutedEventArgs e) + { + this.UpperStart.Visibility = System.Windows.Visibility.Visible;//显示上件操作页面 + this.imgshangjiancaouzo.Source = new BitmapImage(new Uri(@"..\Resources\kucun2.png", UriKind.Relative));//上件按钮点击变选定中的蓝色 + this.splPlcMessage.Visibility = System.Windows.Visibility.Collapsed;//隐藏plc交互信息页面 + this.imgPlcMessage.Source = new BitmapImage(new Uri(@"..\Resources\caozuo.png", UriKind.Relative));//上件按钮点击变选定中的蓝色 + } + /// + /// PLC信息按钮点击事件 + /// + /// + /// + private void BtnPlcMessage_Click(object sender, RoutedEventArgs e) + { + this.UpperStart.Visibility = System.Windows.Visibility.Collapsed;//隐藏上件操作页面 + this.imgshangjiancaouzo.Source = new BitmapImage(new Uri(@"..\Resources\kucun1.png", UriKind.Relative));//上件按钮变未选中白色 + this.splPlcMessage.Visibility = System.Windows.Visibility.Visible;//显示plc交互信息页面 + this.imgPlcMessage.Source = new BitmapImage(new Uri(@"..\Resources\caozuo2.png", UriKind.Relative));//plc交互信息页面变选定中的蓝色 + } + + /// + /// 电气机柜信息面板定时器调用方法 + /// + /// + /// + private void PLCmessage(object sender, EventArgs e) + { + try + { + #region 注释代码折叠 周义帆 2023/11/16 + //string XiaoCheID = "0"; + //string GuaJuDaoWei = "0"; + //string XiaoCheQuXiang = "0"; + //string PLCChuLiZhuangTai = "0"; + //string WCSChuLiZhuangTai = "0"; + //string wcsWriteMessage = ""; + //string plcWriteMessageCLZW = ""; + //#region K02交互点 + //string plcpointAddress = "DB301.DBW0"; + ////小车ID + + //XiaoCheID = _plc.Read(plcpointAddress).ToString(); + //if (XiaoCheID != null) + //{ + // this.tbxK02XCID.Text = XiaoCheID; + //} + ////挂具到位状态 + //plcpointAddress = "DB4.DBW4"; + //GuaJuDaoWei = _plc.Read(plcpointAddress).ToString(); + //if (GuaJuDaoWei != null) + //{ + // this.tbxK02GJDW.Text = GuaJuDaoWei; + //} + ////PLC处理状态 + //plcpointAddress = "DB4.DBW6"; + //PLCChuLiZhuangTai = _plc.Read(plcpointAddress).ToString(); + //if (PLCChuLiZhuangTai != null) + //{ + // this.tbxK02CLZT.Text = PLCChuLiZhuangTai; + //} + ////挂具去向 + //plcpointAddress = "DB5.DBW4"; + //XiaoCheQuXiang = _plc.Read(plcpointAddress).ToString(); + //if (XiaoCheQuXiang != null) + //{ + // this.tbxK02XCQX.Text = XiaoCheQuXiang; + //} + ////WCS处理状态 + //plcpointAddress = "DB5.DBW6"; + //WCSChuLiZhuangTai = _plc.Read(plcpointAddress).ToString(); + //if (WCSChuLiZhuangTai != null) + //{ + // this.tbxK02WCSCLZT.Text = WCSChuLiZhuangTai; + //} + ////WCS写入物料信息 + //plcpointAddress = "DB5.DBW60"; + //wcsWriteMessage = _plc.Read(plcpointAddress).ToString(); + //if (WCSChuLiZhuangTai != null) + //{ + // this.tbxK02WriteMaterial.Text = wcsWriteMessage; + //} + ////PLC写入物料信息处理状态 + //plcpointAddress = "DB4.DBW60"; + //plcWriteMessageCLZW = _plc.Read(plcpointAddress).ToString(); + //if (WCSChuLiZhuangTai != null) + //{ + // this.tbxK02WriteMaterialPlc.Text = plcWriteMessageCLZW; + //} + //#endregion + + //#region K07交互点 + //plcpointAddress = "DB302.DBW0"; + ////小车ID + //XiaoCheID = _plc.Read(plcpointAddress).ToString(); + //if (XiaoCheID != null) + //{ + // this.tbxK07XCID.Text = XiaoCheID; + //} + ////挂具到位状态 + //plcpointAddress = "DB4.DBW8"; + //GuaJuDaoWei = _plc.Read(plcpointAddress).ToString(); + //if (GuaJuDaoWei != null) + //{ + // this.tbxK07GJDW.Text = GuaJuDaoWei; + //} + ////PLC处理状态 + //plcpointAddress = "DB4.DBW10"; + //PLCChuLiZhuangTai = _plc.Read(plcpointAddress).ToString(); + //if (PLCChuLiZhuangTai != null) + //{ + // this.tbxK07CLZT.Text = PLCChuLiZhuangTai; + //} + ////挂具去向 + //plcpointAddress = "DB5.DBW8"; + //XiaoCheQuXiang = _plc.Read(plcpointAddress).ToString(); + //if (XiaoCheQuXiang != null) + //{ + // this.tbxK07XCQX.Text = XiaoCheQuXiang; + //} + ////WCS处理状态 + //plcpointAddress = "DB5.DBW10"; + //WCSChuLiZhuangTai = _plc.Read(plcpointAddress).ToString(); + //if (WCSChuLiZhuangTai != null) + //{ + // this.tbxK07WCSCLZT.Text = WCSChuLiZhuangTai; + //} + ////WCS写入物料信息 + //plcpointAddress = "DB5.DBW62"; + //wcsWriteMessage = _plc.Read(plcpointAddress).ToString(); + //if (WCSChuLiZhuangTai != null) + //{ + // this.tbxK07WriteMaterial.Text = wcsWriteMessage; + //} + ////PLC写入物料信息处理状态 + //plcpointAddress = "DB4.DBW62"; + //plcWriteMessageCLZW = _plc.Read(plcpointAddress).ToString(); + //if (WCSChuLiZhuangTai != null) + //{ + // this.tbxK07WriteMaterialPlc.Text = plcWriteMessageCLZW; + //} + //#endregion + + //#region K18交互点 + //plcpointAddress = "DB304.DBW0"; + ////小车ID + //XiaoCheID = _plc.Read(plcpointAddress).ToString(); + //if (XiaoCheID != null) + //{ + // this.tbxK18XCID.Text = XiaoCheID; + //} + ////挂具到位状态 + //plcpointAddress = "DB4.DBW16"; + //GuaJuDaoWei = _plc.Read(plcpointAddress).ToString(); + //if (GuaJuDaoWei != null) + //{ + // this.tbxK18GJDW.Text = GuaJuDaoWei; + //} + ////PLC处理状态 + //plcpointAddress = "DB4.DBW18"; + //PLCChuLiZhuangTai = _plc.Read(plcpointAddress).ToString(); + //if (PLCChuLiZhuangTai != null) + //{ + // this.tbxK18CLZT.Text = PLCChuLiZhuangTai; + //} + ////挂具去向 + //plcpointAddress = "DB5.DBW16"; + //XiaoCheQuXiang = _plc.Read(plcpointAddress).ToString(); + //if (XiaoCheQuXiang != null) + //{ + // this.tbxK18XCQX.Text = XiaoCheQuXiang; + //} + ////WCS处理状态 + //plcpointAddress = "DB5.DBW18"; + //WCSChuLiZhuangTai = _plc.Read(plcpointAddress).ToString(); + //if (WCSChuLiZhuangTai != null) + //{ + // this.tbxK18WCSCLZT.Text = WCSChuLiZhuangTai; + //} + //#endregion + + //#region K22交互点 + //plcpointAddress = "DB306.DBW0"; + ////小车ID + //XiaoCheID = _plc.Read(plcpointAddress).ToString(); + //if (XiaoCheID != null) + //{ + // this.tbxK22XCID.Text = XiaoCheID; + //} + ////挂具到位状态 + //plcpointAddress = "DB4.DBW24"; + //GuaJuDaoWei = _plc.Read(plcpointAddress).ToString(); + //if (GuaJuDaoWei != null) + //{ + // this.tbxK22GJDW.Text = GuaJuDaoWei; + //} + ////PLC处理状态 + //plcpointAddress = "DB4.DBW26"; + //PLCChuLiZhuangTai = _plc.Read(plcpointAddress).ToString(); + //if (PLCChuLiZhuangTai != null) + //{ + // this.tbxK22CLZT.Text = PLCChuLiZhuangTai; + //} + ////挂具去向 + //plcpointAddress = "DB5.DBW24"; + //XiaoCheQuXiang = _plc.Read(plcpointAddress).ToString(); + //if (XiaoCheQuXiang != null) + //{ + // this.tbxK22XCQX.Text = XiaoCheQuXiang; + //} + ////WCS处理状态 + //plcpointAddress = "DB5.DBW26"; + //WCSChuLiZhuangTai = _plc.Read(plcpointAddress).ToString(); + //if (WCSChuLiZhuangTai != null) + //{ + // this.tbxK22WCSCLZT.Text = WCSChuLiZhuangTai; + //} + //#endregion + + //#region K46交互点 + //plcpointAddress = "DB307.DBW0"; + ////小车ID + //XiaoCheID = _plc.Read(plcpointAddress).ToString(); + //if (XiaoCheID != null) + //{ + // this.tbxK46XCID.Text = XiaoCheID; + //} + ////挂具到位状态 + //plcpointAddress = "DB4.DBW28"; + //GuaJuDaoWei = _plc.Read(plcpointAddress).ToString(); + //if (GuaJuDaoWei != null) + //{ + // this.tbxK46GJDW.Text = GuaJuDaoWei; + //} + ////PLC处理状态 + //plcpointAddress = "DB4.DBW30"; + //PLCChuLiZhuangTai = _plc.Read(plcpointAddress).ToString(); + //if (PLCChuLiZhuangTai != null) + //{ + // this.tbxK46CLZT.Text = PLCChuLiZhuangTai; + //} + ////挂具去向 + //plcpointAddress = "DB5.DBW28"; + //XiaoCheQuXiang = _plc.Read(plcpointAddress).ToString(); + //if (XiaoCheQuXiang != null) + //{ + // this.tbxK46XCQX.Text = XiaoCheQuXiang; + //} + ////WCS处理状态 + //plcpointAddress = "DB5.DBW30"; + //WCSChuLiZhuangTai = _plc.Read(plcpointAddress).ToString(); + //if (WCSChuLiZhuangTai != null) + //{ + // this.tbxK46WCSCLZT.Text = WCSChuLiZhuangTai; + //} + ////WCS写入物料信息 + //plcpointAddress = "DB5.DBW64"; + //wcsWriteMessage = _plc.Read(plcpointAddress).ToString(); + //if (WCSChuLiZhuangTai != null) + //{ + // this.tbxK46WriteMaterial.Text = wcsWriteMessage; + //} + ////PLC写入物料信息处理状态 + //plcpointAddress = "DB4.DBW64"; + //plcWriteMessageCLZW = _plc.Read(plcpointAddress).ToString(); + //if (WCSChuLiZhuangTai != null) + //{ + // this.tbxK46WriteMaterialPlc.Text = plcWriteMessageCLZW; + //} + //#endregion + + //#region K48交互点 + //plcpointAddress = "DB308.DBW0"; + ////小车ID + //XiaoCheID = _plc.Read(plcpointAddress).ToString(); + //if (XiaoCheID != null) + //{ + // this.tbxK48XCID.Text = XiaoCheID; + //} + ////挂具到位状态 + //plcpointAddress = "DB4.DBW32"; + //GuaJuDaoWei = _plc.Read(plcpointAddress).ToString(); + //if (GuaJuDaoWei != null) + //{ + // this.tbxK48GJDW.Text = GuaJuDaoWei; + //} + ////PLC处理状态 + //plcpointAddress = "DB4.DBW34"; + //PLCChuLiZhuangTai = _plc.Read(plcpointAddress).ToString(); + //if (PLCChuLiZhuangTai != null) + //{ + // this.tbxK48CLZT.Text = PLCChuLiZhuangTai; + //} + ////挂具去向 + //plcpointAddress = "DB5.DBW32"; + //XiaoCheQuXiang = _plc.Read(plcpointAddress).ToString(); + //if (XiaoCheQuXiang != null) + //{ + // this.tbxK48XCQX.Text = XiaoCheQuXiang; + //} + ////WCS处理状态 + //plcpointAddress = "DB5.DBW34"; + //WCSChuLiZhuangTai = _plc.Read(plcpointAddress).ToString(); + //if (WCSChuLiZhuangTai != null) + //{ + // this.tbxK48WCSCLZT.Text = WCSChuLiZhuangTai; + //} + ////WCS写入物料信息 + //plcpointAddress = "DB5.DBW66"; + //wcsWriteMessage = _plc.Read(plcpointAddress).ToString(); + //if (WCSChuLiZhuangTai != null) + //{ + // this.tbxK48WriteMaterial.Text = wcsWriteMessage; + //} + ////PLC写入物料信息处理状态 + //plcpointAddress = "DB4.DBW66"; + //plcWriteMessageCLZW = _plc.Read(plcpointAddress).ToString(); + //if (WCSChuLiZhuangTai != null) + //{ + // this.tbxK48WriteMaterialPlc.Text = plcWriteMessageCLZW; + //} + //#endregion + #endregion + + // 调用方法,传递 K02 交互点的信息 + ReadPlcData("DB301.DBW0", 1, "2", tbxK02XCID, tbxK02GJDW, tbxK02CLZT, tbxK02XCQX, tbxK02WCSCLZT); + // 调用方法,传递 K07 交互点的信息 + ReadPlcData("DB302.DBW0", 1, "2", tbxK07XCID, tbxK07GJDW, tbxK07CLZT, tbxK07XCQX, tbxK07WCSCLZT); + // 调用方法,传递 K18 交互点的信息 + ReadPlcData("DB304.DBW0", 1, "2", tbxK18XCID, tbxK18GJDW, tbxK18CLZT, tbxK18XCQX, tbxK18WCSCLZT); + // 调用方法,传递 K22 交互点的信息 + ReadPlcData("DB306.DBW0", 1, "2", tbxK22XCID, tbxK22GJDW, tbxK22CLZT, tbxK22XCQX, tbxK22WCSCLZT); + // 调用方法,传递 K46 交互点的信息 + ReadPlcData("DB307.DBW0", 1, "2", tbxK46XCID, tbxK46GJDW, tbxK46CLZT, tbxK46XCQX, tbxK46WCSCLZT); + // 调用方法,传递 K48 交互点的信息 + ReadPlcData("DB308.DBW0", 1, "2", tbxK48XCID, tbxK48GJDW, tbxK48CLZT, tbxK48XCQX, tbxK48WCSCLZT); + + #region 1号上件点给PLC信息 + ReadAndUpdatePlcData("DB5.DBW60", "DB4.DBW60", tbxK48WriteMaterial, tbxK48WriteMaterialPlc); + #endregion + + #region 2号上件点给PLC信息 + ReadAndUpdatePlcData("DB5.DBW62", "DB4.DBW62", tbxK46WriteMaterial, tbxK46WriteMaterialPlc); + #endregion + + #region 1线下件点给PLC信息 + ReadAndUpdatePlcData("DB5.DBW64", "DB4.DBW64", tbxK07WriteMaterial, tbxK07WriteMaterialPlc); + #endregion + + #region 2线上件点给PLC信息 + ReadAndUpdatePlcData("DB5.DBW66", "DB4.DBW66", tbxK02WriteMaterial, tbxK02WriteMaterialPlc); + #endregion + + #region 嵌套方法折叠 + void ReadAndUpdatePlcData(string addressWcs, string addressPlc, TextBox textBoxMaterial, TextBox textBoxMaterialPlc) + { + // WCS键入物料信息 + string wcsChuLiZhuangTai = _plc.Read(addressWcs).ToString(); + if (wcsChuLiZhuangTai != null && !textBoxMaterial.IsFocused) + { + textBoxMaterial.Text = wcsChuLiZhuangTai; + } + + // PLC接收键入物料信息状态 + string chuLiZhuangTai = _plc.Read(addressPlc).ToString(); + if (chuLiZhuangTai != null) + { + textBoxMaterialPlc.Text = chuLiZhuangTai; + } + } + #endregion + + //显示K46上件点状态 + string K46UpState = _plc.Read("DB4.DBW70").ToString(); + if (K46UpState != null && !this.tbx_K46State.IsFocused) + { + string k46state = K46UpState == "1" ? "启用上件" : "直接放行"; + this.tbx_K46State.Text = k46state; + } + //显示K48上件点状态 + string K48UpState = _plc.Read("DB4.DBW72").ToString(); + if (K48UpState != null && !this.tbx_K48State.IsFocused) + { + string k48state = K48UpState == "1" ? "启用上件" : "直接放行"; + this.tbx_K48State.Text = k48state; + } + string state = ThriftConfig.UpSite == "k46" ? K46UpState : K48UpState; + string result = state == "1" ? "启用上件" : "直接放行"; + this.lab_Title.Content = $"上件点:{ThriftConfig.UpSite},使用模式:{result}"; + this.tBoxMessage.IsEnabled = state == "1" ? true : false; + } + catch (Exception ex) + { + LogManager.Info($"电气机柜信息面板定时器调用方法报错 >>> {ex.Message}"); + } + } + + /// + /// PLC读取方法封装 + /// + /// plc地址位 + /// plc数据类型(int类型默认为1) + /// plc地址位长度(string类型默认为2) + /// 载具号文本输入框 + /// 载具到位文本输入框 + /// PLC车辆状态文本输入框 + /// 载具去向文本输入框 + /// WCS处理状态文本输入框 + private void ReadPlcData(string plcAddress, int plcDataType, string plcValueLength, + TextBox textBoxXcid, TextBox textBoxGjdw, TextBox textBoxClzt, + TextBox textBoxXcqx, TextBox textBoxWcsclzt) + { + try + { + // 载具号 + ReadAndSetText(plcAddress, textBoxXcid); + + // 载具到位 + //DQXX.plcpointAddress = $"DB4.DBW{GetOffset(plcAddress, 0)}"; + string gjdw = $"DB4.DBW{GetOffset(plcAddress, 0)}"; + ReadAndSetText(gjdw, textBoxGjdw); + + // PLC处理状态 + //DQXX.plcpointAddress = $"DB4.DBW{GetOffset(plcAddress, 2)}"; + string plcclzt = $"DB4.DBW{GetOffset(plcAddress, 2)}"; + ReadAndSetText(plcclzt, textBoxClzt); + + // 小车去向 + //DQXX.plcpointAddress = $"DB5.DBW{GetOffset(plcAddress, 0)}"; + string xcqx = $"DB5.DBW{GetOffset(plcAddress, 0)}"; + ReadAndSetText(xcqx, textBoxXcqx, textBoxXcqx.IsFocused); + + // WCS处理完成 + //DQXX.plcpointAddress = $"DB5.DBW{GetOffset(plcAddress, 2)}"; + string wcsclzt = $"DB5.DBW{GetOffset(plcAddress, 2)}"; + ReadAndSetText(wcsclzt, textBoxWcsclzt, textBoxWcsclzt.IsFocused); + //-------------------------------------------------------------------------以下为方法内部嵌套方法 + //嵌套方法1 + void ReadAndSetText(string dw, TextBox textBox, bool checkFocus = false) + { + string value = _plc.Read(dw).ToString(); + if (value != null && (!checkFocus || !textBox.IsFocused)) + { + textBox.Text = value; + } + } + //嵌套方法2 + int GetOffset(string PlcAddress, int baseOffset) + { + int result = int.Parse(PlcAddress.Substring(4, 1)) * 4 + baseOffset; + return result; + } + + } + catch (Exception ex) + { + LogManager.Info($"PLC读取方法封装报错 >>> {ex.Message}"); + } + + } + /// + /// 清除信息按钮 + /// + /// + /// + private void btnsendNullCar_Click(object sender, RoutedEventArgs e) + { + try + { + this.tBoxMessage.Clear(); + this.tbx_CheLiangChangDu.Clear(); + this.lba_ThrifTtitle.Content = string.Empty; + } + catch (Exception) + { + } + } + /// + /// 使用DataTable当做数据传递中介向DataGrid中传输数据源 + /// + private void LoadMaterial_GetMessage(string wheresql) + { + try + { + string pjsql = string.IsNullOrEmpty(wheresql) ? "" : $"where order_code like '%{wheresql}'"; + using var scope = _host.Services.CreateScope(); + using var dbContext = scope.ServiceProvider.GetRequiredService(); + string sql = $@"SELECT + line_code AS lineCode, + order_code AS orderCode, + prod_code AS prodCode, + est, + IsOver AS isover + FROM base_production_order_split + {pjsql} + ORDER BY IsOver , est ;"; + var QueryOrder = dbContext.ExecuteSqlQuery(sql); + #region 注释代码折叠 + //string sql = ($@"SELECT + + // a.line_code AS lineCode, + + // a.order_code AS orderCode, + + // a.prod_code AS prodCode, + + // a.est, + + // a.IsOver AS isover, + + // CONVERT(b.downline, CHAR) AS siteCode + + // FROM base_production_order_split a + + // LEFT JOIN base_waitdownline b + + // ON a.order_code = b.materiel_no {pjsql} ORDER BY est ,IsOver "); + //var QueryOrder = dbContext.BaseProductionOrderSplit.OrderBy(t => t.est).OrderBy(t => t.isover).ToList(); + #endregion + if (QueryOrder?.Count > 0) + { + DataTable dt = new DataTable(); + dt.Columns.Add("order_code"); + dt.Columns.Add("prod_code"); + dt.Columns.Add("line_code"); + dt.Columns.Add("est"); + dt.Columns.Add("isover"); + foreach (var i in QueryOrder) + { + DataRow dr = dt.NewRow(); + dr["order_code"] = i.orderCode.ToString(); + dr["prod_code"] = i.prodCode.ToString(); + dr["line_code"] = i.lineCode.ToString(); + dr["est"] = i.est.ToString(); + dr["isover"] = i.isover.ToString(); + switch (i.isover) + { + case 0: + dr["isover"] = "未上线"; + break; + case 1: + dr["isover"] = "已上线"; + break; + case 2: + dr["isover"] = "已完成"; + break; + default: + dr["isover"] = "状态错误!"; + break; + } + dt.Rows.Add(dr); + } + this.LoadMaterial.ItemsSource = dt.DefaultView; + this.LoadMaterial.Items.Refresh(); + } + } + catch (Exception ex) + { + LogManager.Info($"dagird获取信息报错1 >>> {ex.Message}"); + } + + } + + /// + /// 查询按钮点击事件 + /// + /// + /// + private void ChaXunButton_Click(object sender, RoutedEventArgs e) + { + string vin = this.MoHuChaXunWuLiaoName.Text.Trim().ToUpper().ToString(); + this.LoadMaterial.ItemsSource = null; + LoadMaterial_GetMessage(vin); + } + /// + /// 清空按钮 + /// + /// + /// + private void QingKongButton_Click(object sender, RoutedEventArgs e) + { + this.MoHuChaXunWuLiaoName.Clear(); + this.LoadMaterial.ItemsSource = null; + LoadMaterial_GetMessage(""); + } + /// + /// 上件点状态损坏确认按钮点击事件 + /// + /// + /// + private void Btn_shangjiansunhuai_Click(object sender, RoutedEventArgs e) + { + //this.spl_sunhuaizhakouquxiang.Visibility = System.Windows.Visibility.Visible; + //using var scope = _host.Services.CreateScope(); + //using var dbContext = scope.ServiceProvider.GetRequiredService(); + //dbContext.BaseAmima.Where(t => t.name == "UpState").Update(a => new BaseAmima() { password = "1" }); + //var data = dbContext.BaseAmima.Where(t => t.name == "UpState").FirstOrDefault(); + //string quxiang = data.direction == 1 ? "直通" : "弯通"; + //this.lab_shangjiandianzhuangtai.Content = $"上件点状态:损坏!K22固定去向:" + quxiang; + //this.lab_shangjiandianzhuangtai.Foreground = new SolidColorBrush(Colors.Red); + } + /// + /// 上件点状态良好确认按钮点击事件 + /// + /// + /// + private void Btn_shangjianweixiu_click(object sender, RoutedEventArgs e) + { + using var scope = _host.Services.CreateScope(); + using var dbContext = scope.ServiceProvider.GetRequiredService(); + this.lab_shangjiandianzhuangtai.Content = $"上件点状态:正常!K22走任务线别去向!"; + this.lab_shangjiandianzhuangtai.Foreground = new SolidColorBrush(Colors.Green); + this.spl_sunhuaizhakouquxiang.Visibility = System.Windows.Visibility.Hidden; + // dbContext.BaseAmima.Where(t => t.name == "UpState").Update(a => new BaseAmima() { password = "2" }); + } + /// + /// 上件点状态维护损坏后固定K22去向1 + /// + /// + /// + private void Btn_K22QuXiang1_Click(object sender, RoutedEventArgs e) + { + //this.spl_sunhuaizhakouquxiang.Visibility = System.Windows.Visibility.Visible; + //using var scope = _host.Services.CreateScope(); + //using var dbContext = scope.ServiceProvider.GetRequiredService(); + //dbContext.BaseAmima.Where(t => t.name == "UpState").Update(a => new BaseAmima() { direction = 1 }); + //Btn_shangjiansunhuai_Click(null, null); + } + + /// + /// 上件点状态维护损坏后固定K22去向2 + /// + /// + /// + private void Btn_K22QuXiang2_Click(object sender, RoutedEventArgs e) + { + this.spl_sunhuaizhakouquxiang.Visibility = System.Windows.Visibility.Visible; + using var scope = _host.Services.CreateScope(); + using var dbContext = scope.ServiceProvider.GetRequiredService(); + //dbContext.BaseAmima.Where(t => t.name == "UpState").Update(a => new BaseAmima() { direction = 2 }); + Btn_shangjiansunhuai_Click(null, null); + } + /// + /// 修改车身长度信息点击事件 + /// + /// + /// + private void BtnXiuGaiCheShenChangDu_Click(object sender, RoutedEventArgs e) + { + CheShenChangDuGuanLi cscdgl = new(_host); + cscdgl.Show(); + } + /// + /// 扫码枪扫码后发车操作 + /// + /// + /// + private void txtInput_PreviewKeyDown(object sender, KeyEventArgs e) + { + try + { + //输入字符长度为17且有回车按键响应 + if (this.tBoxMessage.Text.Trim().Length == 17 && e.Key == Key.Enter) + { + using var scope = _host.Services.CreateScope(); + using var dbContext = scope.ServiceProvider.GetRequiredService(); + string VinResult = this.tBoxMessage.Text.Trim().ToUpper().ToString(); + //var orderModel = dbContext.BaseProductionOrderSplit.Where(t => t.orderCode == VinResult).FirstOrDefault(); + //if (orderModel == null) + //{ + // MessageBox.Show($"该VIN条码:{VinResult}未搜索到对应订单!"); + // return; + //} + //if (orderModel.isover != 0) + //{ + // if (orderModel.isover == 1) MessageBox.Show($"该Vin条码:{VinResult}对应订单已上线!", "发车错误提示!"); + // if (orderModel.isover == 2) MessageBox.Show($"该Vin条码:{VinResult}对应订单已下线完成!", "发车错误提示!"); + // return; + //} + // var waitdownlineModel = dbContext.BaseWaitdownline.Where(t => t.definefield1 == orderModel.lineCode).ToList(); + //int FlagNum = waitdownlineModel.Count(); + //if (FlagNum >= FlagConfig.UpFlagNum) + //{ + // MessageBox.Show($"已上线数量:{FlagNum}>=缓存闸口设置数量:{FlagConfig.UpFlagNum},限制发车操作!", "发车错误提示!"); + // LogManager.Info($"当前时间:{DateTime.Now},物料:{orderModel.orderCode},线别:{orderModel.lineCode},数量:{FlagNum} >= 缓存数量:{FlagConfig.UpFlagNum},限制发车操作!"); + // return; + //} + string sqlQuery = @$" + SELECT + b1.material_no AS materialNo, + b1.k46up_length AS k46upLength, + b1.k48up_length AS k48upLength, + b1.down_length AS downLength, + b2.order_code AS definefield1, + b2.line_code AS definefield2, + b2.prod_code AS definefield3 + FROM + base_materialinfo b1 + JOIN base_production_order_split b2 + ON b2.prod_code LIKE CONCAT('%', b1.material_no, '%') + WHERE + b2.order_code = '{VinResult}'"; + var QueryOrder = dbContext.ExecuteSqlQuery(sqlQuery); + #region 周义帆 20231202 注释sql折叠 + //(@$"SELECT b1.material_no as materialNo, + //b1.k46up_length as k46upLength, + //b1.k48up_length as k48upLength, + //b1.down_length as downLength, + //b2.order_code as definefield1, + //b2.line_code as definefield2, + //b2.prod_code as definefield3 + //FROM base_materialinfo b1 + //JOIN base_production_order_split b2 ON b2.prod_code LIKE CONCAT('%', b1.material_no, '%') + //WHERE b2.order_code = '{vinText}'; "); + #endregion + if (QueryOrder?.Count == 0) + { + MessageBox.Show($"未查找到Vin:{VinResult}对应车型", "发车错误提示!"); + return; + } + string changduText = ThriftConfig.UpSite == "k46" ? QueryOrder[0].k46upLength : QueryOrder[0].k48upLength; + if (string.IsNullOrWhiteSpace(changduText)) + { + MessageBox.Show($"未查找到Vin:{VinResult}对应车型长度", "发车错误提示!"); + return; + } + string carId = this.CarNo.Text; + if (string.IsNullOrWhiteSpace(carId)) + { + MessageBox.Show($"挂具号为空!", "发车错误提示!"); + return; + } + string zhandianText = ThriftConfig.UpSite == "k46" ? "K46" : "K48"; + List carList = new() + { + $"上件站点 >>> {zhandianText}" + }; + SendCar(carList, VinResult); + LogManager.Info($"当前时间;{DateTime.Now},发车方法调用记录 >>> 挂具ID:{carId},上件站点:{carList[0]} , Vin条码号:{VinResult},车身长度:{changduText}"); + carList.Clear(); + //this.LoadMaterial.Items.Refresh(); + this.LoadMaterial.ItemsSource = null; + LoadMaterial_GetMessage(""); + } + else if (this.tBoxMessage.Text.Trim().Length < 17 && e.Key == Key.Enter) + { + MessageBox.Show($"输入Vin条码:{this.tBoxMessage.Text.Trim()}长度有误!"); + return; + } + } + catch (Exception ex) + { + MessageBox.Show($"扫码发车方法报错 >>> {ex.Message}"); + } + } + /// + /// 订单导入按钮点击事件 + /// + /// + /// + private void btn_dingdandaoru_Click(object sender, RoutedEventArgs e) + { + try + { + Application.Current.Dispatcher.Invoke(new Action( + delegate + { + // 设置 EPPlus 许可上下文 + ExcelPackage.LicenseContext = LicenseContext.NonCommercial; + OpenFileDialog openFileDialog = new OpenFileDialog(); + openFileDialog.Filter = "Excel Files|*.xls;*.xlsx"; + if (openFileDialog.ShowDialog() == true) + { + FileInfo fileInfo = new FileInfo(openFileDialog.FileName); + + using (ExcelPackage package = new ExcelPackage(fileInfo)) + { + ExcelWorksheet worksheet = package.Workbook.Worksheets.FirstOrDefault(); + + if (worksheet != null) + { + // 获取 Excel 表头 + var columnHeaders = worksheet.Cells[1, 1, 1, worksheet.Dimension.End.Column] + .Select(cell => cell.Text) + .ToList(); + BaseProductionOrderSplit orderMoedel = new(); + // 映射数据库字段,这里需要根据你的实际需求进行调整 + var columnMappings = new Dictionary + { + // 添加映射 + {columnHeaders[0],"production_sequence"}, + {columnHeaders[1],"line_code"}, + {columnHeaders[3],"prod_code"}, + {columnHeaders[4],"Quantity"}, + {columnHeaders[5],"order_code"} + }; + int ordernum = 0; + // 获取实际的行数和列数 + int rowCount = worksheet.Dimension.Rows; + int colCount = worksheet.Dimension.Columns; + // 遍历 Excel 数据行 + for (int row = 2; row <= rowCount; row++) + { + // 创建 SQL 插入语句 + //string insertCommand = $"INSERT INTO YourTableName ({string.Join(", ", columnMappings.Values)}) VALUES ("; + List values = new(); + // 遍历 Excel 数据列 + for (int col = 1; col <= colCount; col++) + { + string columnName = columnHeaders[col - 1]; + string databaseColumnName; + // 映射 Excel 列名到数据库列名 + if (columnMappings.TryGetValue(columnName, out databaseColumnName)) + { + // 获取 Excel 单元格的值 + var cellValue = worksheet.Cells[row, col].Text; + // 添加值到插入语句 + values.Add(cellValue); + //values.Add($"'{cellValue.Replace("'", "''")}'"); + //if (!string.IsNullOrWhiteSpace(cellValue)) + //{ + // values.Add(cellValue); + //} + } + } + // 使用 LINQ 查询空值 + bool containsNull = values.Any(item => item == "" || item == null); + if (containsNull) + { + //MessageBox.Show("Excel表格中存在空值,不执行导入操作!", "订单导入操作提示!"); + //LogManager.Info($"订单导入按钮事件错误 >>> Excel表格中存在空值!不执行导入操作!"); + break; + } + // 获得插入语句 + //string fullInsertCommand = $"{insertCommand} {string.Join(", ", values)} )"; + var xianbiename = Char.GetNumericValue(values[1][values[1].Length - 1]).ToString(); + int orderSequence = int.Parse(values[0].Trim()); + using var scope = _host.Services.CreateScope(); + using var dbContext = scope.ServiceProvider.GetRequiredService(); + // var orderModel = dbContext.BaseProductionOrderSplit.OrderBy(t => t.productionSequence).ToList(); + //var data = orderModel.Find(t => t.orderCode == values[4].Trim().ToUpper()); + //if (data == null) + //{ + // BaseProductionOrderSplit InserOrderModel = new() + // { + // id = Guid.NewGuid().ToString(), + // lineCode = values[1].Trim(), + // lineName = xianbiename == "1" ? "二线" : "一线", + // orderCode = values[4].Trim().ToUpper(), + // prodCode = values[2].Trim(), + // prodDesc = values[2].Trim(), + // productionSequence = orderSequence, + // est = DateTime.Now, + // isover = 0, + // quantity = 1, + // createBy = "ExcelInsert" + // }; + // dbContext.Add(InserOrderModel); + // dbContext.SaveChanges(); + // ordernum++; + //} + } + + MessageBox.Show($"{ordernum}条订单导入系统!", "订单导入操作提示!"); + this.LoadMaterial.ItemsSource = null; + LoadMaterial_GetMessage(""); + } + } + } + })); + } + catch (Exception ex) + { + MessageBox.Show($"订单导入失败 >>> {ex.Message}", "订单导入操作提示!"); + LogManager.Info($"按钮订单导入事件报错 >>> {ex.Message}"); + } + } + /// + /// 接收到载具号后,清空残留信息 + /// + /// + /// + private void CarNo_TextChanged(object sender, TextChangedEventArgs e) + { + if (!string.IsNullOrWhiteSpace(this.tBoxMessage.Text) && this.tBoxMessage.Text.Length == 17) + { + //清空缓存信息 + this.CarNo.Clear(); + this.tBoxMessage.Clear(); + this.tbx_CheLiangChangDu.Clear(); + this.lba_ThrifTtitle.Content = string.Empty; + } + } + /// + /// 订单清空按钮 + /// + /// + /// + private void btn_ClearOrder_Click(object sender, RoutedEventArgs e) + { + try + { + var data = this.LoadMaterial.ItemsSource; + if (data == null) + { + MessageBox.Show($"当前订单信息为空,无需清空操作!", "订单手动清空提示!"); + return; + } + if (MessageBox.Show("确认是否清空当前预存订单?", + "订单手动清空提示", + MessageBoxButton.YesNo, MessageBoxImage.Information) == MessageBoxResult.Yes) + { + using var scope = _host.Services.CreateScope(); + using var dbContext = scope.ServiceProvider.GetRequiredService(); + string sqlQuery = @"INSERT INTO + base_production_order_split_bak + (id,site_code, line_code, line_name, order_code,prod_code,prod_desc,IsOver,est,Quantity,production_sequence) + SELECT + id,site_code, line_code, line_name, order_code,prod_code,prod_desc,IsOver,est,Quantity,production_sequence + FROM base_production_order_split;"; + string sqlDelete = @"Delete + FROM + base_production_order_split;"; + var ret = dbContext.Database.ExecuteSqlRaw(sqlQuery); + dbContext.Database.ExecuteSqlRaw(sqlDelete); + string zhandianText = ThriftConfig.UpSite == "k46" ? "K46" : "K48"; + string saveLog = ret == 0 ? "清空后备份任务SQL执行失败!" : "清空后备份任务SQL语句执行成功!"; + if (ret != 0) MessageBox.Show($"{ret}条订单清空完毕!", "订单清空提示!"); + LogManager.Info($"手动清空任务日志记录 >>> 站点:{zhandianText}{saveLog}"); + this.LoadMaterial.ItemsSource = null; + LoadMaterial_GetMessage(""); + } + } + catch (Exception ex) + { + LogManager.Info($"手动清空任务方法报错 >>> {ex.Message}"); + } + } + /// + /// 查询挂具绑定Vin物料点击事件 + /// + /// + /// + private void Btn_ChaXunByCarNo_Click(object sender, RoutedEventArgs e) + { + try + { + if (string.IsNullOrWhiteSpace(this.tbx_JieBangByCarNo.Text)) + { + MessageBox.Show("上线挂具号输入框为空!", "查询挂具物料绑定关系操作提示!"); + return; + } + if (!Regex.IsMatch(this.tbx_JieBangByCarNo.Text, @"^\d+$")) + { + MessageBox.Show("挂具号输入格式有误!", "查询挂具物料绑定关系操作提示!"); + this.tbx_JieBangByVin.Clear(); + return; + //textBox.Text = textBox.Text.Replace("非数字字符", ""); // 移除非数字字符 + } + if (this.tbx_JieBangByCarNo.Text.Length >= 3) + { + MessageBox.Show("挂具号输入长度有误!", "查询挂具物料绑定关系操作提示!"); + this.tbx_JieBangByVin.Clear(); + return; + } + int ShuRuCarNo = int.Parse(this.tbx_JieBangByCarNo.Text); + using var scope = _host.Services.CreateScope(); + using var dbContext = scope.ServiceProvider.GetRequiredService(); + //var listWaitDownLine = dbContext.BaseWaitdownline.Where(t => t.isDelete == 0 && t.carNo == ShuRuCarNo).ToList(); + //if (string.IsNullOrWhiteSpace(listWaitDownLine[0].materielNo)) + //{ + // MessageBox.Show($"{ShuRuCarNo}号为空挂具,不存在与Vin绑定信息!", "查询挂具物料绑定关系操作提示!"); + // return; + //} + // var listOrder = dbContext.BaseProductionOrderSplit.Where(t => t.orderCode == listWaitDownLine[0].materielNo).ToList(); + //var resultOrderList = (from waitdownline in listWaitDownLine + // join order in listOrder on waitdownline.materielNo equals order.orderCode + // select new BaseProductionOrderSplit + // { + // id = order.id, + // lineCode = order.lineCode, + // orderCode = order.orderCode + // }).ToList(); + //if (resultOrderList?.Count > 0) + //{ + // this.tbx_JieBangByVin.Text = resultOrderList[0].orderCode; + //} + } + catch (Exception ex) + { + MessageBox.Show($"查询挂具物料绑定关系报错 >>> {ex.Message}"); + LogManager.Info($"查询挂具物料绑定关系报错 >>> {ex.Message}"); + } + } + /// + /// 解绑按钮点击事件 + /// + /// + /// + private void Btn_JieBangByCarNo_Click(object sender, RoutedEventArgs e) + { + try + { + + } + catch (Exception ex) + { + LogManager.Info($"解绑载具物料绑定关系操作报错 >>> {ex.Message}"); + } + } + /// + /// 清空输入框点击事件 + /// + /// + /// + private void Btn_ChaXunByCarNoClear_Click(object sender, RoutedEventArgs e) + { + try + { + this.tbx_JieBangByCarNo.Clear(); + this.tbx_JieBangByVin.Clear(); + } + catch (Exception) + { + } + } + /// + /// 一键重置点击事件 + /// + /// + /// + private void Btn_JieBangAll_Click(object sender, RoutedEventArgs e) + { + try + { + + } + catch (Exception EX) + { + LogManager.Info($"一键重置订单、挂具状态方法报错 >>> {EX.Message}"); + } + + } + } +} diff --git a/src/Khd.Core.Wpf/Form/FormBoardT.xaml b/src/Khd.Core.Wpf/Form/FormBoardT.xaml new file mode 100644 index 0000000..a43a03a --- /dev/null +++ b/src/Khd.Core.Wpf/Form/FormBoardT.xaml @@ -0,0 +1,3326 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Khd.Core.Wpf/WindowPage/HoistWarnHandlerWindow.xaml.cs b/src/Khd.Core.Wpf/WindowPage/HoistWarnHandlerWindow.xaml.cs new file mode 100644 index 0000000..406b525 --- /dev/null +++ b/src/Khd.Core.Wpf/WindowPage/HoistWarnHandlerWindow.xaml.cs @@ -0,0 +1,336 @@ +using Khd.Core.Domain.Models; +using Khd.Core.EntityFramework; +using Khd.Core.Library.Mapper; +using Khd.Core.Plc.S7; +using Microsoft.EntityFrameworkCore; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Net; +using System.Text; +using System.Threading.Tasks; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Data; +using System.Windows.Documents; +using System.Windows.Input; +using System.Windows.Media; +using System.Windows.Media.Imaging; +using System.Windows.Shapes; +using Khd.Core.Plc; +using System.Windows.Threading; + +namespace Khd.Core.Wpf.WindowPage +{ + + + /// + /// HoistWarnInfoWindow.xaml 的交互逻辑 + /// + /// 提升机异常处理步骤: + /// 前置条件:提升机无报警==》PLC触摸屏有报警先复位消除报警、有急停先拔起来急停按钮(5F上电、复位、蓝色确认按钮) + /// 1.点击删除任务按钮,删除提升机已经下发的正在执行的任务 + /// 2.选择问题楼层,不需要选择,读PLC自动判断 + /// 3.点击对应楼层步序清0,提升机状态清0 + /// 4.点击对应楼层出,将托盘出到接驳位 + /// 5.重新下发任务 + /// + /// + public partial class HoistWarnHandlerWindow : Window + { + private readonly long T01 = 6; + //提升机当前楼层 + private long currentFloor = 1; + + private bool taskHandlerFlag = false; + + /// + /// 提升机当前楼层 + /// + private BasePlcpoint currentfloor06; + /// + /// 提升机步序清0 + /// + private BasePlcpoint hoisterStepClear; + + private DispatcherTimer _timer; + private int _timeRemaining = 30; // 初始时间为30秒 + + + private IHost _host; + public HoistWarnHandlerWindow(IHost host) + { + _host = host; + InitializeComponent(); + getCurrentFloor(); + } + + + private void getCurrentFloor() + { + using var scope = _host.Services.CreateScope(); + using var dbContext = scope.ServiceProvider.GetRequiredService(); + dbContext.ChangeTracker.Clear(); + + //一楼提升机当前楼层 写 + this.currentfloor06 = SystemData.BasePlcpoints.First(t => t.equipmentNo.Contains("Hoister") && t.plcpointNo.Contains("currentfloor06")); + var currentfloor06Value = SystemData.PlcDic[0].Read(this.currentfloor06.plcpointAddress); //提升机当前楼层 读 + currentFloor = Convert.ToInt32(currentfloor06Value); + FloorTxt.Text = currentFloor.ToString(); + + } + + + private void Window_StateChanged(object sender, System.EventArgs e) + { + if (WindowState == WindowState.Minimized) + { + Close(); + } + } + + + + + + /// + /// 1.手动提升机操作到起始地楼层或目的楼层 + ///如果有任务,校验是否在起始地或者目的地楼层,不在的话校验不通过 + /// + /// + /// + private void ManualHoistButton_Click(object sender, RoutedEventArgs e) + { + try + { + + getCurrentFloor(); + using var scope = _host.Services.CreateScope(); + using var dbContext = scope.ServiceProvider.GetRequiredService(); + dbContext.ChangeTracker.Clear(); + var wcsTask = dbContext.WcsTask.Where(t => t.nextPointId == T01 && t.taskStatus > 0 && t.taskStatus <= 5).FirstOrDefault(); + if (wcsTask != null) + { + if (wcsTask.currPointId != currentFloor && wcsTask.endPointId != currentFloor) + { + this.Msg.Text = DateTime.Now + " 提升机当前在" + currentFloor + "楼,需要到达起始地楼层:" + wcsTask.currPointId + " 或者到达终点楼层:" + wcsTask.endPointId; + this.ManualHoistButton.Background = new SolidColorBrush(Colors.Red); + return; + } + } + + this.Msg.Text = DateTime.Now + " 手动提升机到达" + currentFloor + "楼,通过校验"; + this.ManualHoistButton.Background = new SolidColorBrush(Colors.LimeGreen); + this.ManualHoistButton.IsEnabled = false; + HoistClearButton.IsEnabled = true; + } + catch (Exception ex) + { + this.Msg.Text = DateTime.Now + " 校验手动提升机操作到起始地楼层或目的楼层:" + ex.Message; + this.ManualHoistButton.Background = new SolidColorBrush(Colors.Red); + + } + } + + + /// + /// 2.提升机步序清0,轿厢线步序清0 + /// + /// + /// + private void HoistClear_Click(object sender, RoutedEventArgs e) + { + try + { + ///轿厢线步序清0 + this.hoisterStepClear = SystemData.BasePlcpoints.First(t => t.plcpointNo== "hoisterStepClear"); + SystemData.PlcDic[0].Write(hoisterStepClear.plcpointAddress, 1); + Task.Run(() => + { + Thread.Sleep(1000); + SystemData.PlcDic[0].Write(hoisterStepClear.plcpointAddress, 0); + }); + + + this.HoistClearButton.Background = new SolidColorBrush(Colors.LimeGreen); + this.Msg.Text = DateTime.Now + " 轿厢线步序清0成功,请等待30s以后,提升机还未动作,请点击任务处理按钮..."; + this.HoistClearButton.IsEnabled = false; + #region 开始定时器30s倒计时 + // 初始化定时器 + _timeRemaining = 30; // 重置时间为30秒 + _timer = new DispatcherTimer(); + _timer.Interval = TimeSpan.FromSeconds(1); // 每秒触发一次 + _timer.Tick += Timer_Tick; // 设置定时器事件处理器 + _timer.Start(); // 启动定时器 + + #endregion + + + } + catch (Exception ex) + { + this.Msg.Text = DateTime.Now + " 轿厢线步序清0出现异常:" + ex.Message; + this.HoistClearButton.Background = new SolidColorBrush(Colors.Red); + } + } + + + private void Timer_Tick(object sender, EventArgs e) + { + if (_timeRemaining > 0) + { + _timeRemaining--; + UpdateTimeDisplay(); + } + else + { + _timer.Stop(); // 倒计时结束,停止定时器 + this.Msg.Text = DateTime.Now + " 倒计时结束,允许下一步操作"; + if (taskHandlerFlag) + { + PalletOutButton.IsEnabled = true; + } + else + { + TaskHandlerButton.IsEnabled = true; + } + } + } + + private void UpdateTimeDisplay() + { + if (taskHandlerFlag) + { + this.timeTxt2.Text = _timeRemaining.ToString(); + } + else + { + this.timeTxt1.Text = _timeRemaining.ToString(); + } + + } + + + + /// + /// 3.任务处理 + /// + /// + /// + private void TaskHandlerButton_Click(object sender, RoutedEventArgs e) + { + try + { + using var scope = _host.Services.CreateScope(); + using var dbContext = scope.ServiceProvider.GetRequiredService(); + dbContext.ChangeTracker.Clear(); + var wcsTask = dbContext.WcsTask.Where(t => t.nextPointId == T01 && t.taskStatus > 0 && t.taskStatus <= 5).FirstOrDefault(); + if (wcsTask != null) + { + if (wcsTask.currPointId == currentFloor) //在起始地楼层 + { + #region 读接驳位RFID ,防止托盘还没走,但是任务状态不为0,需要重新把状态重置0下发 + //提升机当前楼层 + this.currentfloor06 = SystemData.BasePlcpoints.First(t => t.equipmentNo.Contains("Hoister") && t.plcpointNo.Contains("currentfloor06")); + var currentfloor06Value = SystemData.PlcDic[0].Read(this.currentfloor06.plcpointAddress); //提升机当前楼层 读 + currentFloor = Convert.ToInt32(currentfloor06Value); + + FloorTxt.Text = currentFloor.ToString(); + //接驳位RFID + BasePlcpoint LineRFID = SystemData.BasePlcpoints.First(t => t.plcpointNo == $"RFID00{currentFloor}"); + var rfid = SystemData.PlcDic[0].ReadRFID(LineRFID.plcpointAddress); + #endregion + + if (!string.IsNullOrEmpty(wcsTask.containerNo) && rfid.Contains(wcsTask.containerNo)) // 在出发地接驳位并且任务RFID不为空,与接驳位RFID相同 + { + wcsTask.taskStatus = 0; + //if(wcsTask.endPointId == currentFloor) //到达终点 + //{ + // wcsTask.taskStatus = 5; + //}else if(wcsTask.currPointId == currentFloor) //托盘还在起始地 + //{ + // wcsTask.taskStatus = 0; + //} + } + else//在提升机里面 + { + wcsTask.taskStatus = 2; + } + } + else if (wcsTask.endPointId == currentFloor) //在目的地楼层 + { + #region 读接驳位RFID ,防止托盘已经到达目的楼层,但是任务状态不为5,需要自动更新 + //提升机当前楼层 + this.currentfloor06 = SystemData.BasePlcpoints.First(t => t.equipmentNo.Contains("Hoister") && t.plcpointNo.Contains("currentfloor06")); + var currentfloor06Value = SystemData.PlcDic[0].Read(this.currentfloor06.plcpointAddress); //提升机当前楼层 读 + currentFloor = Convert.ToInt32(currentfloor06Value); + + FloorTxt.Text = currentFloor.ToString(); + + //接驳位RFID + BasePlcpoint LineRFID = SystemData.BasePlcpoints.First(t => t.plcpointNo == $"RFID00{currentFloor}"); + var rfid = SystemData.PlcDic[0].ReadRFID(LineRFID.plcpointAddress); + #endregion + + if (!string.IsNullOrEmpty(wcsTask.containerNo) && rfid.Contains(wcsTask.containerNo)) // 在目的地接驳位并且任务RFID不为空,与接驳位RFID相同 + { + wcsTask.taskStatus = 4; + + } + else//在提升机里面 + { + wcsTask.taskStatus = 3; + } + + } + dbContext.WcsTask.Update(wcsTask); + dbContext.SaveChanges(); + } + + this.TaskHandlerButton.Background = new SolidColorBrush(Colors.LimeGreen); + this.Msg.Text = DateTime.Now + " 任务处理成功,请等待30s以后提升机或者AGV还未动作,点击出提升机按钮..."; + taskHandlerFlag = true; + this.TaskHandlerButton.IsEnabled = false; + #region 开始定时器30s倒计时 + // 初始化定时器 + _timeRemaining = 30; // 重置时间为30秒 + _timer = new DispatcherTimer(); + _timer.Interval = TimeSpan.FromSeconds(1); // 每秒触发一次 + _timer.Tick += Timer_Tick; // 设置定时器事件处理器 + _timer.Start(); // 启动定时器 + + #endregion + }catch(Exception ex) + { + this.Msg.Text = DateTime.Now + " 任务处理异常:" + ex.Message; + this.TaskHandlerButton.Background = new SolidColorBrush(Colors.Red); + } + + } + + /// + /// 4.下发提升机出轿厢任务 + /// + /// + /// + private void PalletOutButton_Click(object sender, RoutedEventArgs e) + { + try + { + + BasePlcpoint basePlcpoint = SystemData.BasePlcpoints.First(t => t.floorNo == currentFloor && t.plcpointNo.Contains("wcsrun")); + SystemData.PlcDic[0].WriteToPoint(basePlcpoint.plcpointAddress, "2", basePlcpoint.plcpointLength.ToString());//去向为2,表示提升机已到达目的地,让货出去 + this.Msg.Text = DateTime.Now + " 提升机下发" + currentFloor + "楼出库指令"; + this.PalletOutButton.Background = new SolidColorBrush(Colors.LimeGreen); + this.PalletOutButton.IsEnabled = false; + } + catch (Exception ex) + { + this.Msg.Text = DateTime.Now + " 下发提升机出轿厢任务异常:" + ex.Message; + this.PalletOutButton.Background = new SolidColorBrush(Colors.Red); + } + } + } +} diff --git a/src/Khd.Core.Wpf/WindowPage/HoistWarnInfoWindow.xaml b/src/Khd.Core.Wpf/WindowPage/HoistWarnInfoWindow.xaml new file mode 100644 index 0000000..27701c7 --- /dev/null +++ b/src/Khd.Core.Wpf/WindowPage/HoistWarnInfoWindow.xaml @@ -0,0 +1,252 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Khd.Core.Wpf/WindowPage/HoistWarnInfoWindow.xaml.cs b/src/Khd.Core.Wpf/WindowPage/HoistWarnInfoWindow.xaml.cs new file mode 100644 index 0000000..847ce48 --- /dev/null +++ b/src/Khd.Core.Wpf/WindowPage/HoistWarnInfoWindow.xaml.cs @@ -0,0 +1,133 @@ +using Khd.Core.Domain.Models; +using Khd.Core.EntityFramework; +using Khd.Core.Library.Mapper; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Data; +using System.Windows.Documents; +using System.Windows.Input; +using System.Windows.Media; +using System.Windows.Media.Imaging; +using System.Windows.Shapes; + +namespace Khd.Core.Wpf.WindowPage +{ + /// + /// HoistWarnInfoWindow.xaml 的交互逻辑 + /// + public partial class HoistWarnInfoWindow : Window + { + private IHost _host; + public HoistWarnInfoWindow(IHost host) + { + _host = host; + InitializeComponent(); + Task.Run(async () => + { + await InitList(); + }); + } + + /// + /// 显示序号事件 + /// + /// + /// + private void dgData_LoadingRow(object sender, DataGridRowEventArgs e) + { + e.Row.Header = e.Row.GetIndex() + 1; + } + + + /// + /// 初始加载500条数据 + /// + /// + /// + /// + private async Task InitList() + { + try + { + using var scope = _host.Services.CreateScope(); + using var dbContext = scope.ServiceProvider.GetRequiredService(); + List list = await dbContext.DmsRecordAlarmInfo.Where(x => x.DeviceId == 6 ).OrderByDescending(x => x.CreateTime).Take(500).ToListAsync(); + list.ForEach(x => + { + if (x.AlarmStatus == "0") + { + x.AlarmStatus = "未处理"; + } + else + { + x.AlarmStatus = "已恢复"; + } + }); + Dispatcher.Invoke(() => + { + this.LoadMaterial0.ItemsSource = null; + this.LoadMaterial0.ItemsSource = list; + this.LoadMaterial0.Items.Refresh(); + }); + } + catch (Exception ex) + { + MessageBox.Show($"查询报警出现异常,请重新尝试:{ex.Message}"); + } + } + + + + private async Task GetHistory(DateTime startTime, DateTime endTime) + { + try + { + using var scope = _host.Services.CreateScope(); + using var dbContext = scope.ServiceProvider.GetRequiredService(); + List< DmsRecordAlarmInfo > list = await dbContext.DmsRecordAlarmInfo.Where(x => x.DeviceId ==6 && x.CreateTime>= startTime && x.CreateTime <= endTime).OrderByDescending(x => x.CreateTime).ToListAsync(); + list.ForEach(x => + { + if (x.AlarmStatus == "0") + { + x.AlarmStatus = "未处理"; + } + else + { + x.AlarmStatus = "已恢复"; + } + }); + Dispatcher.Invoke(() => + { + this.LoadMaterial0.ItemsSource = null; + this.LoadMaterial0.ItemsSource = list; + this.LoadMaterial0.Items.Refresh(); + }); + } + catch (Exception ex) + { + MessageBox.Show($"查询报警出现异常,请重新尝试:{ex.Message}"); + } + } + + private async void SelectByTime_Click(object sender, RoutedEventArgs e) + { + DateTime? begin = this.BeginTime.SelectedDate; + DateTime? end = this.EndTime.SelectedDate; + if (begin == null || end == null) + { + MessageBox.Show($"请选择开始或者结束时间"); + return; + } + await GetHistory(begin.Value, end.Value); + + } + + } +} diff --git a/src/Khd.Core.Wpf/WindowPage/InventoryMaterialWindow.xaml b/src/Khd.Core.Wpf/WindowPage/InventoryMaterialWindow.xaml new file mode 100644 index 0000000..03b3ec6 --- /dev/null +++ b/src/Khd.Core.Wpf/WindowPage/InventoryMaterialWindow.xaml @@ -0,0 +1,193 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Khd.Core.Wpf/WindowPage/StockWindow.xaml.cs b/src/Khd.Core.Wpf/WindowPage/StockWindow.xaml.cs new file mode 100644 index 0000000..19a1bc9 --- /dev/null +++ b/src/Khd.Core.Wpf/WindowPage/StockWindow.xaml.cs @@ -0,0 +1,162 @@ +using Khd.Core.Domain.Models; +using Khd.Core.EntityFramework; +using Microsoft.EntityFrameworkCore; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Data; +using System.Windows.Documents; +using System.Windows.Input; +using System.Windows.Media; +using System.Windows.Media.Imaging; +using System.Windows.Shapes; + +namespace Khd.Core.Wpf.WindowPage +{ + /// + /// StockWindow.xaml 的交互逻辑 + /// + public partial class StockWindow : Window + { + private IHost host = null; + private long LocationId = 0; + public StockWindow(IHost _host, long locationId) + { + host = _host; + InitializeComponent(); + LocationId = locationId; + Init(locationId); + } + + public async Task Init(long locationId) + { + using var scope = host.Services.CreateScope(); + var dbContext = scope.ServiceProvider.GetRequiredService(); + var location = await dbContext.WmsBaseLocation.Where(x => x.locationId == locationId).FirstOrDefaultAsync(); + positionRowTxt.Text = location.locRow.ToString(); + positionColumnTxt.Text = location.locColumn.ToString(); + positionLayerTxt.Text = location.layerNum.ToString(); + locationTxt.Text = location.locationCode; + palletTxt.Text = location.containerCode; + + if (location.warehouseId == 512 || location.warehouseId == 311 || location.warehouseId == 511) + { + + + var stockList = await dbContext.WmsRawStock.Where(x => x.palletInfoCode == location.containerCode && x.palletInfoCode != null).ToListAsync(); + if (stockList != null && stockList.Count > 0) + { + + txtStatus.Text = getStatus(location.locationStatus) + ",有库存"; + // 获取所有库存物料 ID + var materialIds = stockList.Select(stock => stock.materialId).Distinct().ToList(); + var materialInfos = await dbContext.MesBaseMaterialInfo + .Where(material => materialIds.Contains(material.MaterialId)) + .ToListAsync(); + + // 将库存物料信息和物料详细信息合并 + var stockDetails = from stock in stockList + from material in materialInfos + where stock.materialId == material.MaterialId + select new + { + materialCode = material.MaterialCode, + materialName = material.MaterialName, + materialSpec = material.MaterialSpec, + totalAmount = stock.totalAmount, + frozenAmount = stock.frozenAmount + + }; + + + StockDataGrid.ItemsSource = stockDetails; + } + else + { + txtStatus.Text = getStatus(location.locationStatus) + ",无库存"; + } + + } + else + { + var stockList = await dbContext.WmsProductStock.Where(x => x.palletInfoCode == location.containerCode && x.palletInfoCode != null).ToListAsync(); + if (stockList != null && stockList.Count > 0) + { + txtStatus.Text = getStatus(location.locationStatus) + ",有库存"; + // 获取所有库存物料 ID + var materialIds = stockList.Select(stock => stock.productId).Distinct().ToList(); + var materialInfos = await dbContext.MesBaseMaterialInfo + .Where(material => materialIds.Contains(material.MaterialId)) + .ToListAsync(); + + // 将库存物料信息和物料详细信息合并 + var stockDetails = from stock in stockList + from material in materialInfos + where stock.productId == material.MaterialId + select new + { + materialCode = material.MaterialCode, + materialName = material.MaterialName, + materialSpec = material.MaterialSpec, + totalAmount = stock.totalAmount, + frozenAmount = stock.frozenAmount + + }; + + + StockDataGrid.ItemsSource = stockDetails; + } + else + { + txtStatus.Text = getStatus(location.locationStatus) + ",无库存"; + } + + + } + } + + public string getStatus(string status) + { + switch (status) + { + case "1": return "正常"; + case "2": return "自动锁定"; + case "3": return "人工锁定"; + case "4": return "移库锁定"; + case "5": return "合库锁定"; + case "6": return "出库锁定"; + case "8": return "因外侧库位异常导致内侧库位无法使用"; + case "9": return "异常库位"; + default : return "未知"; + } + } + + private void LockLocation_Click(object sender, RoutedEventArgs e) + { + using var scope = host.Services.CreateScope(); + var dbContext = scope.ServiceProvider.GetRequiredService(); + var record = dbContext.WmsBaseLocation.Where(x => x.locationId == LocationId).First(); + record.locationStatus = "3"; + dbContext.WmsBaseLocation.Update(record); + dbContext.SaveChanges(); + Init(LocationId); + } + + private void UnLockLocation_Click(object sender, RoutedEventArgs e) + { + using var scope = host.Services.CreateScope(); + var dbContext = scope.ServiceProvider.GetRequiredService(); + var record = dbContext.WmsBaseLocation.Where(x => x.locationId == LocationId).First(); + record.locationStatus = "1"; + dbContext.WmsBaseLocation.Update(record); + dbContext.SaveChanges(); + Init(LocationId); + } + } +} diff --git a/src/Khd.Core.Wpf/WindowPage/TaskHistoryWindow.xaml b/src/Khd.Core.Wpf/WindowPage/TaskHistoryWindow.xaml new file mode 100644 index 0000000..0d4d2aa --- /dev/null +++ b/src/Khd.Core.Wpf/WindowPage/TaskHistoryWindow.xaml @@ -0,0 +1,307 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Khd.Core.Wpf/WindowPage/TaskHistoryWindow.xaml.cs b/src/Khd.Core.Wpf/WindowPage/TaskHistoryWindow.xaml.cs new file mode 100644 index 0000000..b404615 --- /dev/null +++ b/src/Khd.Core.Wpf/WindowPage/TaskHistoryWindow.xaml.cs @@ -0,0 +1,89 @@ +using Khd.Core.Domain.Models; +using Khd.Core.EntityFramework; +using Khd.Core.Library.Mapper; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Data; +using System.Windows.Documents; +using System.Windows.Input; +using System.Windows.Media; +using System.Windows.Media.Imaging; +using System.Windows.Shapes; +using Khd.Core.Wpf.dto; +namespace Khd.Core.Wpf.WindowPage +{ + /// + /// TaskHistoryWindow.xaml 的交互逻辑 + /// + public partial class TaskHistoryWindow : Window + { + private IHost _host; + public TaskHistoryWindow(IHost host) + { + _host = host; + InitializeComponent(); + Task.Run(async() => + { + await GetTask(DateTime.Now.AddDays(-3), DateTime.Now.AddDays(3)); + }); + } + + + + /// + /// 显示序号事件 + /// + /// + /// + private void dgData_LoadingRow(object sender, DataGridRowEventArgs e) + { + e.Row.Header = e.Row.GetIndex() + 1; + } + + + + private async Task GetTask(DateTime startTime,DateTime endTime) + { + try + { + using var scope = _host.Services.CreateScope(); + using var dbContext = scope.ServiceProvider.GetRequiredService(); + var data = await dbContext.WcsTaskLog.Where(x => x.createTime >= startTime && x.createTime <= endTime).OrderByDescending(x => x.createTime).ToListAsync(); + Dispatcher.Invoke(() => + { + + long? nextPointId = 0; + + List taskModel = CoreMapper.Map>(data); + + this.LoadMaterial0.ItemsSource = null; + this.LoadMaterial0.ItemsSource = taskModel; + this.LoadMaterial0.Items.Refresh(); + }); + }catch(Exception ex) + { + MessageBox.Show($"查询任务出现异常,请重新尝试:{ex.Message}"); + } + } + + private async void SelectByTime_Click(object sender, RoutedEventArgs e) + { + DateTime? begin = this.BeginTime.SelectedDate; + DateTime? end = this.EndTime.SelectedDate; + if (begin == null || end == null) + { + MessageBox.Show($"请选择开始或者结束时间"); + return; + } + await GetTask(begin.Value, end.Value); + + } + } +} diff --git a/src/Khd.Core.Wpf/dto/Location.cs b/src/Khd.Core.Wpf/dto/Location.cs new file mode 100644 index 0000000..5d50a69 --- /dev/null +++ b/src/Khd.Core.Wpf/dto/Location.cs @@ -0,0 +1,29 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows; + +namespace Khd.Core.Wpf.dto +{ + public class Location + { + public long LocationId { get; set; } // 新增 LocationId + public string Code { get; set; } + public LocationStatus Status { get; set; } + + public Visibility isFreeze { get; set; } + } + + public enum LocationStatus + { + // 在库有库存 + InAndStock, + //// 空料箱在库无库存 + EmptyInStock, + //库外 + OutOfStock, + + } +} diff --git a/src/Khd.Core.Wpf/dto/LocationDto.cs b/src/Khd.Core.Wpf/dto/LocationDto.cs new file mode 100644 index 0000000..c560d4d --- /dev/null +++ b/src/Khd.Core.Wpf/dto/LocationDto.cs @@ -0,0 +1,19 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Khd.Core.Wpf.dto +{ + internal class LocationDto + { + public long LocationId { get; set; } + public string LocationCode { get; set; } + public string LocationStatus { get; set; } + public string ContainerCode { get; set; } + public int MaterialId { get; set; } + public int SaleOrderId {get; set; } + public int FloorNo { get; set; } + } +} diff --git a/src/Khd.Core.Wpf/dto/taskModel.cs b/src/Khd.Core.Wpf/dto/taskModel.cs new file mode 100644 index 0000000..fe9c6ca --- /dev/null +++ b/src/Khd.Core.Wpf/dto/taskModel.cs @@ -0,0 +1,70 @@ +using System; +using System.Windows; + +namespace Khd.Core.Wpf.dto +{ + public class taskModel + { + public int? fromFloorNo { get; set; } + + + public long objid { get; set; } + + public long? masterId { get; set; } + + public long? orderId { get; set; } + + public long? serialNo { get; set; } + + public string equipmentNo { get; set; } + + public string containerNo { get; set; } + + public int? taskType { get; set; } + + public int? taskStatus { get; set; } + + public long? materialId { get; set; } + + public string? materialNo { get; set; } + + public int? qty { get; set; } + + public string currPointNo { get; set; } + + public long? currPointId { get; set; } + + public long? nextPointId { get; set; } + + public string nextPointNo { get; set; } + + public string endPointNo { get; set; } + + public long? endPointId { get; set; } + + public int? floorNo { get; set; } + + public int? useFlag { get; set; } + + public string createBy { get; set; } + + public DateTime? createTime { get; set; } + + public string updateBy { get; set; } + + public DateTime? updateTime { get; set; } + + public string CTUExecute { get; set; } + + public string isEmpty { get; set; } + + public string ud3 { get; set; } + + public int? ud1 { get; set; } + + public string ud2 { get; set; } + + public string remark { get; set; } + public Visibility isShow { get; set; } + } +} diff --git a/src/Khd.Core.Wpf/myConverter/AgvTaskStatusConverter.cs b/src/Khd.Core.Wpf/myConverter/AgvTaskStatusConverter.cs new file mode 100644 index 0000000..431b34a --- /dev/null +++ b/src/Khd.Core.Wpf/myConverter/AgvTaskStatusConverter.cs @@ -0,0 +1,117 @@ +using Khd.Core.Domain.Models; +using Khd.Core.Wpf.dto; +using System; +using System.Collections.Generic; +using System.Globalization; +using System.Linq; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Data; +using System.Windows.Media; + +namespace Khd.Core.Wpf.myConverter +{ + [ValueConversion(typeof(int), typeof(string))] + public class AgvTaskStatusConverter : IValueConverter + { + private readonly Dictionary> dic = new() + { + {2, + new Dictionary(){ + {-1,"人工创建" }, + {0,"未下发" }, + {1,"前往起始地" }, + {2,"入库中" }, + {3,"前往目的地" }, + {4,"出库中" }, + {5,"任务结束" }, + } + }, + { + 4, + new Dictionary(){ + {-1,"人工创建" }, + {0,"未下发" }, + {1,"已下发" }, + {2,"已开始" }, + {3,"已到达起始地" }, + {4,"起始地继续任务" }, + {5,"已到达目的地" }, + {6,"任务结束" } + } + }, + { + 5, + new Dictionary(){ + {-1,"人工创建" }, + {0,"未下发" }, + {1,"已下发" }, + {2,"已开始" }, + {3,"已到达起始地" }, + {4,"起始地继续任务" }, + {5,"已到达目的地" }, + {6,"目的地等待完成" }, + {7,"目的地捡料完成" }, + {8,"任务结束" } + } + }, + { + 6, + new Dictionary(){ + {-1,"人工创建" }, + {0,"未下发" }, + {1,"已下发" }, + {2,"已开始" }, + {3,"已到达起始地" }, + {4,"起始地继续任务" }, + {5,"已到达目的地" }, + {6,"任务结束" } + } + }, + { + 11, + new Dictionary(){ + {-1,"人工创建" }, + {0,"未下发" }, + {1,"已下发" }, + {2,"已开始" }, + {3,"已到达起始地" }, + {4,"起始地继续任务" }, + {5,"已到达目的地" }, + {6,"任务结束" } + } + } + }; + private DataGridRow GetDataGridRow(DependencyObject dependencyObject) + { + if (dependencyObject == null) + return null; + + var dataGridRow = dependencyObject as DataGridRow; + if (dataGridRow != null) + return dataGridRow; + + return GetDataGridRow(VisualTreeHelper.GetParent(dependencyObject)); + } + public object Convert(object value, Type targetType, object parameter, CultureInfo culture) + { + if (value is taskModel wcsTask) + { + BaseEquip baseEquip = SystemData.BaseEquip.First(t => t.objid == wcsTask.nextPointId); + if (dic.TryGetValue(baseEquip.equipType, out var taskStatusDic)) + { + if (taskStatusDic.TryGetValue(wcsTask.taskStatus, out var taskStatus)) + { + return taskStatus; + } + } + } + return "未知"; + } + + public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) + { + return value; + } + } +} diff --git a/src/Khd.Core.Wpf/myConverter/CtuTaskStatusConverter.cs b/src/Khd.Core.Wpf/myConverter/CtuTaskStatusConverter.cs new file mode 100644 index 0000000..5abca91 --- /dev/null +++ b/src/Khd.Core.Wpf/myConverter/CtuTaskStatusConverter.cs @@ -0,0 +1,15 @@ +namespace Khd.Core.Wpf.myConverter +{ + //public class CtuTaskStatusConverter : IValueConverter + //{ + // public object Convert(object value, Type targetType, object parameter, CultureInfo culture) + // { + + // } + + // public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) + // { + // return value; + // } + //} +} diff --git a/src/Khd.Core.Wpf/myConverter/EquipConverter.cs b/src/Khd.Core.Wpf/myConverter/EquipConverter.cs new file mode 100644 index 0000000..8b0aa68 --- /dev/null +++ b/src/Khd.Core.Wpf/myConverter/EquipConverter.cs @@ -0,0 +1,29 @@ +using System; +using System.Globalization; +using System.Linq; +using System.Windows.Data; + +namespace Khd.Core.Wpf.myConverter +{ + public class EquipConverter : IValueConverter + { + public object Convert(object value, Type targetType, object parameter, CultureInfo culture) + { + string? val = System.Convert.ToString(value); + var baseEquip = SystemData.BaseEquip.FirstOrDefault(t => t.equipNo == val); + if (baseEquip == null) + { + return val; + } + else + { + return baseEquip.equipName; + } + } + + public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) + { + return value; + } + } +} diff --git a/src/Khd.Core.Wpf/myConverter/HoisterTaskStatusConverter.cs b/src/Khd.Core.Wpf/myConverter/HoisterTaskStatusConverter.cs new file mode 100644 index 0000000..e4f39a0 --- /dev/null +++ b/src/Khd.Core.Wpf/myConverter/HoisterTaskStatusConverter.cs @@ -0,0 +1,29 @@ +using System; +using System.Collections.Generic; +using System.Globalization; +using System.Windows.Data; + +namespace Khd.Core.Wpf.myConverter +{ + public class HoisterTaskStatusConverter : IValueConverter + { + Dictionary dic = new Dictionary() + { + {-1,"人工任务,未开始" }, + {0,"未下发" }, + {1,"前往起始地" }, + {2,"入库中" }, + {3,"前往目的地" }, + {4,"出库中" }, + }; + public object Convert(object value, Type targetType, object parameter, CultureInfo culture) + { + throw new NotImplementedException(); + } + + public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) + { + throw new NotImplementedException(); + } + } +} diff --git a/src/Khd.Core.Wpf/myConverter/TypeDataConverter.cs b/src/Khd.Core.Wpf/myConverter/TypeDataConverter.cs new file mode 100644 index 0000000..59a989a --- /dev/null +++ b/src/Khd.Core.Wpf/myConverter/TypeDataConverter.cs @@ -0,0 +1,23 @@ +using Khd.Core.Domain.Dto.TaskType; +using System; +using System.Globalization; +using System.Windows.Data; + +namespace Khd.Core.Wpf.myConverter +{ + [ValueConversion(typeof(int), typeof(string))] + public class TypeDataConverter : IValueConverter + { + + public object Convert(object value, Type targetType, object parameter, CultureInfo culture) + { + int val = System.Convert.ToInt32(value); + return StaticTaskType.GetTaskName(val); + } + + public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) + { + return value; + } + } +}