.vs/HH.WCS.Mobox3.DSZSH/FileContentIndex/3f7a8a50-7623-4582-a788-1727f4b734e0.vsidxBinary files differ
.vs/HH.WCS.Mobox3.DSZSH/FileContentIndex/74bd051a-76c6-4faf-9203-3846175eb944.vsidxBinary files differ
.vs/HH.WCS.Mobox3.DSZSH/FileContentIndex/79fc4010-d1c2-42bb-9f8f-a7b972ec34f6.vsidxBinary files differ
.vs/HH.WCS.Mobox3.DSZSH/FileContentIndex/cfeb14b9-8063-424f-8831-ddd93cd9c6f5.vsidxBinary files differ
App_Start/Config.cs
File was deleted App_Start/Settings.cs
File was deleted App_Start/SwaggerConfig.cs
@@ -1,49 +1,14 @@ using System.Web.Http; using WebActivatorEx; using HH.WCS.Mobox3.DSZSH; using HH.WCS.Mobox3.Template; using Swashbuckle.Application; using System.IO; using System.Reflection; using System; using Swashbuckle.Examples; [assembly: PreApplicationStartMethod(typeof(SwaggerConfig), "Register")] namespace HH.WCS.Mobox3.DSZSH namespace HH.WCS.Mobox3.Template { public class SwaggerConfig { public static void Register(HttpConfiguration config) { var thisAssembly = typeof(SwaggerConfig).Assembly; config .EnableSwagger(c => { c.SingleApiVersion("v1", "HH.WCS.Mobox3.DSZSH"); // 设置 XML 注释路径 var baseDirectory = AppDomain.CurrentDomain.BaseDirectory; //var commentsFileName = Assembly.GetExecutingAssembly().GetName().Name + ".xml"; var commentsFileName = "bin\\Debug\\HH.WCS.Mobox3.DSZSH.xml"; var commentsFile = Path.Combine(baseDirectory, commentsFileName); if (File.Exists(commentsFile)) { c.IncludeXmlComments(commentsFile); } // 其他配置... c.UseFullTypeNameInSchemaIds(); // 启用示例数据 //c.DescribeAllEnumsAsStrings(); //c.OperationFilter<ExamplesOperationFilter>(); //c.ModelFilter<ExamplesModelFilter>(); }) .EnableSwaggerUi(c => { // UI 配置 }); } public static void Register() { var thisAssembly = typeof(SwaggerConfig).Assembly; @@ -67,7 +32,7 @@ // hold additional metadata for an API. Version and title are required but you can also provide // additional fields by chaining methods off SingleApiVersion. // c.SingleApiVersion("v1", "HH.WCS.Mobox3.DSZSH"); c.SingleApiVersion("v1", "HH.WCS.Mobox3.Template"); // If you want the output Swagger docs to be indented properly, enable the "PrettyPrint" option. // @@ -96,7 +61,7 @@ //c.BasicAuth("basic") // .Description("Basic HTTP Authentication"); // // NOTE: You must also configure 'EnableApiKeySupport' below in the SwaggerUI section // NOTE: You must also configure 'EnableApiKeySupport' below in the SwaggerUI section //c.ApiKey("apiKey") // .Description("API Key Authentication") // .Name("apiKey") @@ -137,10 +102,6 @@ // more Xml comment files. // //c.IncludeXmlComments(GetXmlCommentsPath()); // 启用 XML 注释 var xmlFile = $"{System.AppDomain.CurrentDomain.BaseDirectory}\\HH.WCS.Mobox3.DSZSH.xml"; c.IncludeXmlComments(xmlFile); // Swashbuckle makes a best attempt at generating Swagger compliant JSON schemas for the various types // exposed in your API. However, there may be occasions when more control of the output is needed. App_Start/SwaggerControllerDescProvider.cs
@@ -80,158 +80,4 @@ return controllerDescDict; } } /// <summary> /// 增强版Swagger提供程序,支持显示控制器和模型的完整文档注释 /// </summary> public class EnhancedSwaggerCacheProvider : ISwaggerProvider { private readonly ISwaggerProvider _swaggerProvider; private static readonly ConcurrentDictionary<string, SwaggerDocument> _cache = new ConcurrentDictionary<string, SwaggerDocument>(); private readonly string _xmlPath; public EnhancedSwaggerCacheProvider(ISwaggerProvider swaggerProvider, string xmlpath) { _swaggerProvider = swaggerProvider; _xmlPath = xmlpath; } public SwaggerDocument GetSwagger(string rootUrl, string apiVersion) { var cacheKey = $"{rootUrl}_{apiVersion}"; return _cache.GetOrAdd(cacheKey, _ => { var srcDoc = _swaggerProvider.GetSwagger(rootUrl, apiVersion); // 添加控制器描述 var (controllerDesc, modelDesc) = GetXmlComments(); srcDoc.vendorExtensions = new Dictionary<string, object> { { "ControllerDesc", controllerDesc }, { "ModelDesc", modelDesc } }; // 为模型添加描述 EnhanceModelDescriptions(srcDoc, modelDesc); return srcDoc; }); } /// <summary> /// 从XML文档中提取控制器和模型描述 /// </summary> private (ConcurrentDictionary<string, string> controllerDesc, ConcurrentDictionary<string, string> modelDesc) GetXmlComments() { var controllerDesc = new ConcurrentDictionary<string, string>(); var modelDesc = new ConcurrentDictionary<string, string>(); if (!File.Exists(_xmlPath)) return (controllerDesc, modelDesc); var xmldoc = new XmlDocument(); xmldoc.Load(_xmlPath); foreach (XmlNode node in xmldoc.SelectNodes("//member")) { var type = node.Attributes?["name"]?.Value; if (string.IsNullOrEmpty(type)) continue; if (type.StartsWith("T:")) { var arrPath = type.Split('.'); var typeName = arrPath[arrPath.Length - 1]; // 获取最后一部分 // 处理控制器 if (typeName.EndsWith("Controller")) { var summaryNode = node.SelectSingleNode("summary"); if (summaryNode != null && !string.IsNullOrWhiteSpace(summaryNode.InnerText)) { //var key = typeName[..^"Controller".Length]; string key = typeName; const string controllerSuffix = "Controller"; if (typeName.EndsWith(controllerSuffix)) { key = typeName.Substring(0, typeName.Length - controllerSuffix.Length); } controllerDesc.TryAdd(key, summaryNode.InnerText.Trim()); } } // 处理模型类 else if (IsModelType(node)) { var summaryNode = node.SelectSingleNode("summary"); if (summaryNode != null && !string.IsNullOrWhiteSpace(summaryNode.InnerText)) { modelDesc.TryAdd(typeName, summaryNode.InnerText.Trim()); } // 处理模型属性 EnhancePropertyDescriptions(node, modelDesc); } } } return (controllerDesc, modelDesc); } /// <summary> /// 判断是否为模型类型 /// </summary> private bool IsModelType(XmlNode node) { // 这里可以根据实际需求调整判断逻辑 // 例如:排除Controller、排除特定命名空间等 var type = node.Attributes?["name"]?.Value ?? ""; return type.StartsWith("T:") && !type.EndsWith("Controller") && !type.Contains(".Controllers.") && !type.Contains(".Infrastructure."); } /// <summary> /// 增强模型属性的描述 /// </summary> private void EnhancePropertyDescriptions(XmlNode typeNode, ConcurrentDictionary<string, string> modelDesc) { var typeName = typeNode.Attributes?["name"]?.Value?.Split('.')?.LastOrDefault()?.Substring(2); if (string.IsNullOrEmpty(typeName)) return; foreach (XmlNode propNode in typeNode.SelectNodes("field|property")) { var propName = propNode.Attributes?["name"]?.Value; if (string.IsNullOrEmpty(propName)) continue; var summaryNode = propNode.SelectSingleNode("summary"); var exampleNode = propNode.SelectSingleNode("example"); if (summaryNode != null && !string.IsNullOrWhiteSpace(summaryNode.InnerText)) { var fullPropKey = $"{typeName}.{propName}"; var description = summaryNode.InnerText.Trim(); if (exampleNode != null && !string.IsNullOrWhiteSpace(exampleNode.InnerText)) { description += $"\n\n示例: {exampleNode.InnerText.Trim()}"; } modelDesc.TryAdd(fullPropKey, description); } } } /// <summary> /// 增强Swagger文档中的模型描述 /// </summary> private void EnhanceModelDescriptions(SwaggerDocument swaggerDoc, ConcurrentDictionary<string, string> modelDesc) { if (swaggerDoc.definitions == null) return; foreach (var definition in swaggerDoc.definitions) { // 处理模型类本身描述 if (modelDesc.TryGetValue(definition.Key, out var classDesc)) { definition.Value.description = classDesc; } // 处理模型属性描述 if (definition.Value.properties != null) { foreach (var property in definition.Value.properties) { var fullPropKey = $"{definition.Key}.{property.Key}"; if (modelDesc.TryGetValue(fullPropKey, out var propDesc)) { property.Value.description = propDesc; } } } } } } } Consts/AgvStateCode.cs
File was deleted Consts/AgvStateName.cs
File was deleted Consts/AreaName.cs
File was deleted Consts/LockStateCode.cs
File was deleted Consts/LockStateName.cs
File was deleted Consts/SpotStateCode.cs
File was deleted Consts/TaskName.cs
File was deleted Controllers/DebugController.cs
File was deleted Dispatch/GZRobot.cs
@@ -1,18 +1,15 @@ using HH.WCS.Mobox3.DSZSH.device; using HH.WCS.Mobox3.DSZSH.ServiceCore; using HH.WCS.Mobox3.DSZSH.AppStart; using HH.WCS.Mobox3.DSZSH.core; using Newtonsoft.Json; using System; using System.Collections.Generic; using System.Web.Caching; using HH.WCS.Mobox3.DSZSH.Helpers; using HH.WCS.Mobox3.DSZSH.Devices; using HH.WCS.Mobox3.DSZSH.Models; using HH.WCS.Mobox3.DSZSH.Services; using static HH.WCS.Mobox3.DSZSH.Dtos.Request.AgvRequest; using static HH.WCS.Mobox3.DSZSH.Dtos.Response.MoboxResponse; using HH.WCS.Mobox3.DSZSH.models; namespace HH.WCS.Mobox3.DSZSH.Dispatch using HH.WCS.Mobox3.DSZSH.util; using static HH.WCS.Mobox3.DSZSH.api.ApiModel; namespace HH.WCS.Mobox3.DSZSH.dispatch { /// <summary> /// 国自调度辅助类 @@ -154,7 +151,7 @@ if (agv.state != 0) { agv.task_no = model.orderName; agv.forklift_no = model.agvIDList; AgvService.OperateAgvTaskStatus(agv); WCSCore.OperateAgvTaskStatus(agv); } result.resultCode = 0; Dispatch/HanAo.cs
@@ -1,10 +1,11 @@ using HH.WCS.Mobox3.DSZSH.AppStart; using HH.WCS.Mobox3.DSZSH.util; using Newtonsoft.Json; using System; using System.Collections.Generic; using System.Web.Services.Description; namespace HH.WCS.Mobox3.DSZSH.Dispatch { namespace HH.WCS.Mobox3.DSZSH.dispatch { /// <summary> /// 国自调度辅助类 /// </summary> Dispatch/NDC.cs
@@ -1,11 +1,10 @@ using HH.WCS.Mobox3.DSZSH.AppStart; using Newtonsoft.Json; using Newtonsoft.Json; using System; using System.Collections.Generic; using System.Text; using System.Xml; namespace HH.WCS.Mobox3.DSZSH.Dispatch namespace HH.WCS.Mobox3.DSZSH.dispatch { public class NDC { Dispatch/NDCApi.cs
@@ -1,12 +1,13 @@ using HH.WCS.Mobox3.DSZSH; using HH.WCS.Mobox3.DSZSH.AppStart; using HH.WCS.Mobox3.DSZSH.util; using Newtonsoft.Json; using System; using System.Collections.Generic; using System.Text; using System.Xml; namespace HH.WCS.Mobox3.DSZSH.Dispatch namespace HH.WCS.Mobox3.DSZSH.dispatch { /// <summary> /// NDC的API接口,用于替代原NDC、NDCHelper和HostToAGV模块 @@ -17,7 +18,7 @@ static NDCApi() { NDCApiUrl = AppStart.Settings.Config.NdcApiUrl; NDCApiUrl = Settings.NdcApiUrl; } Dispatch/NDCHelper.cs
@@ -2,7 +2,7 @@ using System.Collections.Generic; using System.Text; namespace HH.WCS.Mobox3.DSZSH.Dispatch namespace HH.WCS.Mobox3.DSZSH.dispatch { public class NDCHelper { Dtos/Request/AgvRequest.cs
File was deleted Dtos/Request/DebugRequest.cs
File was deleted Dtos/Request/MoboxRequest.cs
File was deleted Dtos/Request/WmsRequest.cs
File was deleted Dtos/Response/AgvResponse.cs
File was deleted Dtos/Response/DebugResponse.cs
File was deleted Dtos/Response/MoboxResponse.cs
File was deleted Dtos/Response/WmsResponse.cs
File was deleted HH.WCS.Mobox3.DSZSH.csproj
@@ -224,87 +224,63 @@ </Reference> </ItemGroup> <ItemGroup> <Compile Include="App_Start\Config.cs" /> <Compile Include="App_Start\SwaggerConfig.cs" /> <Compile Include="Consts\AgvStateCode.cs" /> <Compile Include="Consts\AgvStateName.cs" /> <Compile Include="Consts\AreaName.cs" /> <Compile Include="Consts\LockStateCode.cs" /> <Compile Include="Consts\LockStateName.cs" /> <Compile Include="Consts\SpotStateCode.cs" /> <Compile Include="Consts\TaskName.cs" /> <Compile Include="Controllers\DebugController.cs" /> <Compile Include="Controllers\ErpController.cs" /> <Compile Include="Controllers\MesController.cs" /> <Compile Include="Controllers\MoboxController.cs" /> <Compile Include="Controllers\AgvController.cs" /> <Compile Include="api\ApiHelper.cs" /> <Compile Include="api\ApiModel.cs" /> <Compile Include="api\DebugController.cs" /> <Compile Include="api\ErpController.cs" /> <Compile Include="api\MesController.cs" /> <Compile Include="api\MoboxController.cs" /> <Compile Include="api\AgvController.cs" /> <Compile Include="App_Start\SwaggerControllerDescProvider.cs" /> <Compile Include="Dtos\Request\WmsRequest.cs" /> <Compile Include="Dtos\Response\WmsResponse.cs" /> <Compile Include="Models\DebugModel.cs" /> <Compile Include="Dtos\Request\DebugRequest.cs" /> <Compile Include="Dtos\Response\DebugResponse.cs" /> <Compile Include="Helpers\AgvHelper.cs" /> <Compile Include="Helpers\ExprHelper.cs" /> <Compile Include="Helpers\PathHelper.cs" /> <Compile Include="Helpers\DbHelper.cs" /> <Compile Include="Models\TN_Container_Item.cs" /> <Compile Include="Models\TN_Check_Detail.cs" /> <Compile Include="Models\TN_Check_Order.cs" /> <Compile Include="Models\TN_Inbound_Order.cs" /> <Compile Include="Models\TN_Order_Task.cs" /> <Compile Include="Models\TN_Outbound_Order.cs" /> <Compile Include="Models\TN_Outbound_Detail.cs" /> <Compile Include="Models\TN_Shift_Detail.cs" /> <Compile Include="Models\TN_Shift_Order.cs" /> <Compile Include="ServiceCore\CheckCore.cs" /> <Compile Include="ServiceCore\DebugCore.cs" /> <Compile Include="ServiceCore\OutboundCore.cs" /> <Compile Include="ServiceCore\ShiftCore.cs" /> <Compile Include="Services\DebugService.cs" /> <Compile Include="Devices\ProductionLineDevice.cs" /> <Compile Include="Devices\ModbusHelper.cs" /> <Compile Include="Devices\OpcUaHelper.cs" /> <Compile Include="Devices\PlcHelper.cs" /> <Compile Include="Devices\S7Helper.cs" /> <Compile Include="Devices\TcpClient.cs" /> <Compile Include="Devices\TcpServer.cs" /> <Compile Include="Dispatch\GZRobot.cs" /> <Compile Include="Dispatch\HanAo.cs" /> <Compile Include="Dispatch\NDC.cs" /> <Compile Include="ServiceCore\OfflineCore.cs" /> <Compile Include="Dispatch\NDCApi.cs" /> <Compile Include="Dtos\Request\AgvRequest.cs" /> <Compile Include="Dtos\Request\MoboxRequest.cs" /> <Compile Include="Dtos\Response\AgvResponse.cs" /> <Compile Include="Dtos\Response\MoboxResponse.cs" /> <Compile Include="Models\BaseModel.cs" /> <Compile Include="Models\TN_CG_Detail.cs" /> <Compile Include="Models\TN_CAR_IN.cs" /> <Compile Include="Models\TN_Container.cs" /> <Compile Include="Models\TN_Location.cs" /> <Compile Include="Models\TN_Loc_Container.cs" /> <Compile Include="Models\TN_WorkOrder.cs" /> <Compile Include="Models\TN_Task.cs" /> <Compile Include="Models\TN_Task_Action.cs" /> <Compile Include="Helpers\DeviceProcess.cs" /> <Compile Include="ServiceCore\TaskCore.cs" /> <Compile Include="Controllers\WMSController.cs" /> <Compile Include="Dispatch\HostToAGV.cs" /> <Compile Include="Helpers\TaskHelper.cs" /> <Compile Include="Services\AgvService.cs" /> <Compile Include="Services\WmsService.cs" /> <Compile Include="Services\MoboxService.cs" /> <Compile Include="Helpers\LogHelper.cs" /> <Compile Include="Helpers\ContainerHelper.cs" /> <Compile Include="Helpers\LocationHelper.cs" /> <Compile Include="Helpers\SysHelper.cs" /> <Compile Include="core\Monitor.cs" /> <Compile Include="core\WCSCore.cs" /> <Compile Include="core\WMSCore.cs" /> <Compile Include="process\TaskProcess.cs" /> <Compile Include="util\SqlHelper.cs" /> <Compile Include="models\TN_Container_Item.cs" /> <Compile Include="models\TN_Check_Detail.cs" /> <Compile Include="models\TN_Check_Order.cs" /> <Compile Include="models\TN_Inbound_Order.cs" /> <Compile Include="models\TN_Order_Task.cs" /> <Compile Include="models\TN_Outbound_Order.cs" /> <Compile Include="models\TN_Outbound_Detail.cs" /> <Compile Include="models\TN_Shift_Detail.cs" /> <Compile Include="models\TN_Shift_Order.cs" /> <Compile Include="device\ProductionLineDevice.cs" /> <Compile Include="device\ModbusHelper.cs" /> <Compile Include="device\OpcUaHelper.cs" /> <Compile Include="device\PlcHelper.cs" /> <Compile Include="device\S7Helper.cs" /> <Compile Include="device\TcpClient.cs" /> <Compile Include="device\TcpServer.cs" /> <Compile Include="dispatch\GZRobot.cs" /> <Compile Include="dispatch\HanAo.cs" /> <Compile Include="dispatch\NDC.cs" /> <Compile Include="dispatch\NDCApi.cs" /> <Compile Include="models\BaseModel.cs" /> <Compile Include="models\TN_CG_Detail.cs" /> <Compile Include="models\TN_CAR_IN.cs" /> <Compile Include="models\TN_Container.cs" /> <Compile Include="models\TN_Location.cs" /> <Compile Include="models\TN_Loc_Container.cs" /> <Compile Include="models\TN_WorkOrder.cs" /> <Compile Include="models\TN_Task.cs" /> <Compile Include="models\TN_Task_Action.cs" /> <Compile Include="process\DeviceProcess.cs" /> <Compile Include="api\WMSController.cs" /> <Compile Include="dispatch\HostToAGV.cs" /> <Compile Include="util\LogHelper.cs" /> <Compile Include="wms\ContainerHelper.cs" /> <Compile Include="wms\LocationHelper.cs" /> <Compile Include="wms\SYSHelper.cs" /> <Compile Include="Program.cs" /> <Compile Include="Properties\AssemblyInfo.cs" /> <Compile Include="App_Start\Settings.cs" /> <Compile Include="util\Settings.cs" /> <Compile Include="App_Start\Startup.cs" /> <Compile Include="Dispatch\NDCHelper.cs" /> <Compile Include="Helpers\HttpHelper.cs" /> <Compile Include="dispatch\NDCHelper.cs" /> <Compile Include="util\HttpHelper.cs" /> <Compile Include="wms\WCSHelper.cs" /> <Compile Include="wms\WMSHelper.cs" /> </ItemGroup> <ItemGroup> <None Include=".editorconfig" /> @@ -312,12 +288,9 @@ <None Include="config\config.json"> <CopyToOutputDirectory>Always</CopyToOutputDirectory> </None> <None Include="debug\loc_cntr_cg.csv" /> <None Include="debug\task.csv" /> <None Include="packages.config" /> </ItemGroup> <ItemGroup> <None Include="debug\outbound_order.csv" /> <Content Include="readme.md" /> <EmbeddedResource Include="swagger.js"> <CopyToOutputDirectory>Always</CopyToOutputDirectory> Helpers/AgvHelper.cs
File was deleted Helpers/DbHelper.cs
File was deleted Helpers/ExprHelper.cs
File was deleted Helpers/PathHelper.cs
File was deleted Helpers/TaskHelper.cs
File was deleted Models/BaseModel.cs
@@ -2,7 +2,7 @@ using SqlSugar; namespace HH.WCS.Mobox3.DSZSH.Models { namespace HH.WCS.Mobox3.DSZSH.models { /// <summary> /// 【框架】模板抽象类:基本表数据模型 /// </summary> Models/DebugModel.cs
File was deleted Models/TN_CAR_IN.cs
@@ -1,6 +1,6 @@ using SqlSugar; namespace HH.WCS.Mobox3.DSZSH.Models { namespace HH.WCS.Mobox3.DSZSH.models { /// <summary> /// 【框架】容器生产车数关联子表 /// </summary> Models/TN_CG_Detail.cs
@@ -1,12 +1,12 @@ using SqlSugar; namespace HH.WCS.Mobox3.DSZSH.Models { namespace HH.WCS.Mobox3.DSZSH.models { /// <summary> /// 【框架】物料-容器 关系表 /// </summary> [SugarTable("TN_CG_Detail")] public class TN_CG_Detail : BaseModel { #region 基本属性 /// <summary> /// 料箱商品标识 /// </summary> @@ -28,7 +28,7 @@ public string S_CNTR_CODE { get; set; } /// <summary> /// 货品状态:0合格 1待检 2不合格 3正在检验;下线即待检 /// 货品状态:0合格 1待检 2不合格 3抽检中;下线即待检 /// </summary> public string S_ITEM_STATE { get; set; } = "待检"; @@ -51,10 +51,9 @@ /// 物料规格 /// </summary> public string S_ITEM_SPEC { get; set; } = string.Empty; #endregion // ------------------------------- #region 拓展 /// <summary> /// 执行标准 /// </summary> @@ -74,6 +73,5 @@ ///// 产线号 ///// </summary> //public int N_PRODUCT_LINE { get; set; } = 0; // NOTE 后续MES可能会提供,先创建 #endregion } } Models/TN_Check_Detail.cs
@@ -6,7 +6,7 @@ using SqlSugar; namespace HH.WCS.Mobox3.DSZSH.Models { namespace HH.WCS.Mobox3.DSZSH.models { /// <summary> /// 抽检单明细 /// </summary> Models/TN_Check_Order.cs
@@ -6,7 +6,7 @@ using SqlSugar; namespace HH.WCS.Mobox3.DSZSH.Models { namespace HH.WCS.Mobox3.DSZSH.models { /// <summary> /// 抽检单 /// </summary> Models/TN_Container.cs
@@ -2,7 +2,7 @@ using SqlSugar; namespace HH.WCS.Mobox3.DSZSH.Models { namespace HH.WCS.Mobox3.DSZSH.models { /// <summary> /// 【框架】容器表 /// </summary> Models/TN_Container_Item.cs
@@ -6,7 +6,7 @@ using SqlSugar; namespace HH.WCS.Mobox3.DSZSH.Models { namespace HH.WCS.Mobox3.DSZSH.models { /// <summary> /// 容器-物料类型 关系表 /// </summary> Models/TN_Inbound_Order.cs
@@ -4,7 +4,7 @@ using System.Text; using System.Threading.Tasks; namespace HH.WCS.Mobox3.DSZSH.Models { namespace HH.WCS.Mobox3.DSZSH.models { /// <summary> /// 出库单 /// </summary> Models/TN_Loc_Container.cs
@@ -2,7 +2,7 @@ using SqlSugar; namespace HH.WCS.Mobox3.DSZSH.Models { namespace HH.WCS.Mobox3.DSZSH.models { /// <summary> /// 【框架】货位-容器 关系表 /// </summary> Models/TN_Location.cs
@@ -2,7 +2,7 @@ using SqlSugar; namespace HH.WCS.Mobox3.DSZSH.Models { namespace HH.WCS.Mobox3.DSZSH.models { /// <summary> /// 【框架】货位表 /// </summary> Models/TN_Order_Task.cs
@@ -4,7 +4,7 @@ using System.Text; using System.Threading.Tasks; namespace HH.WCS.Mobox3.DSZSH.Models { namespace HH.WCS.Mobox3.DSZSH.models { public class TN_Order_Task { } Models/TN_Outbound_Detail.cs
@@ -1,6 +1,6 @@ using SqlSugar; namespace HH.WCS.Mobox3.DSZSH.Models { namespace HH.WCS.Mobox3.DSZSH.models { /// <summary> /// 出库单明细 /// </summary> @@ -12,7 +12,7 @@ public string S_OO_NO { get; set; } /// <summary> /// 业务状态:0等待执行 1已执行待生成任务 2任务执行中 3任务完成 /// 业务状态:0待执行 1已下发 2执行中 3已完成 /// </summary> public int N_B_STATE { get; set; } = 1; // 创建即执行 Models/TN_Outbound_Order.cs
@@ -2,7 +2,7 @@ using SqlSugar; namespace HH.WCS.Mobox3.DSZSH.Models { namespace HH.WCS.Mobox3.DSZSH.models { /// <summary> /// 出库单 /// </summary> @@ -14,9 +14,9 @@ public string S_NO { get; set; } /// <summary> /// 业务状态:0等待执行 1已执行待生成任务 2任务执行中 3任务完成 /// 业务状态:0待执行 1已下发 2执行中 3已完成 /// </summary> public int N_B_STATE { get; set; } = 1; // 创建即执行 public int N_B_STATE { get; set; } = 1; /// <summary> /// 物料号 Models/TN_Shift_Detail.cs
@@ -5,7 +5,7 @@ using System.Text; using System.Threading.Tasks; namespace HH.WCS.Mobox3.DSZSH.Models { namespace HH.WCS.Mobox3.DSZSH.models { /// <summary> /// 移库单明细 /// </summary> Models/TN_Shift_Order.cs
@@ -4,7 +4,7 @@ using System.Text; using System.Threading.Tasks; namespace HH.WCS.Mobox3.DSZSH.Models { namespace HH.WCS.Mobox3.DSZSH.models { /// <summary> /// 移库单 /// </summary> Models/TN_Task.cs
@@ -2,7 +2,7 @@ using SqlSugar; namespace HH.WCS.Mobox3.DSZSH.Models { namespace HH.WCS.Mobox3.DSZSH.models { /// <summary> /// 【框架】任务表 /// </summary> Models/TN_Task_Action.cs
@@ -1,6 +1,6 @@ using SqlSugar; namespace HH.WCS.Mobox3.DSZSH.Models { namespace HH.WCS.Mobox3.DSZSH.models { /// <summary> /// 【框架】任务动作表 /// </summary> Models/TN_WorkOrder.cs
@@ -1,6 +1,6 @@ using SqlSugar; namespace HH.WCS.Mobox3.DSZSH.Models { namespace HH.WCS.Mobox3.DSZSH.models { /// <summary> /// 生产工单 /// </summary> Program.cs
@@ -1,17 +1,15 @@ using System; using System.Collections.Generic; using System.Threading; using HH.WCS.Mobox3.DSZSH.AppStart; using HH.WCS.Mobox3.DSZSH.device; using HH.WCS.Mobox3.DSZSH.Helpers; using HH.WCS.Mobox3.DSZSH.ServiceCore; using HH.WCS.Mobox3.DSZSH.core; using Microsoft.Owin.Hosting; using Topshelf; using Task = System.Threading.Tasks.Task; using Monitor = HH.WCS.Mobox3.DSZSH.core.Monitor; namespace HH.WCS.Mobox3.DSZSH { internal class Program @@ -26,7 +24,7 @@ // 3.0 开启S7 StartS7(); // 4.0 开启Modbus //StartModbus(); StartModbus(); // 5.0 开启线程 var rc = HostFactory.Run(x => { @@ -54,7 +52,7 @@ Console.WriteLine("Startup ApiController"); Task.Run(() => { var url = AppStart.Settings.Config.WebApiUrl; // 运行时修改 config.json 无效 var url = Settings.WebApiUrl; // 运行时修改 config.json 无效 Console.WriteLine(url); using (WebApp.Start<Startup>(url)) { @@ -69,8 +67,8 @@ /// </summary> private static void StartTcp() { var tcpServerIP = AppStart.Settings.Config.TcpServerIp; // 运行时修改 config.json 无效 var tcpServerPort = AppStart.Settings.Config.TcpServerPort; // 运行时修改 config.json 无效 var tcpServerIP = Settings.TcpServerIp; // 运行时修改 config.json 无效 var tcpServerPort = Settings.TcpServerPort; // 运行时修改 config.json 无效 new TcpServer(tcpServerIP, tcpServerPort); } @@ -91,18 +89,6 @@ // Console.WriteLine("S7ProductionLineHelper," + item.ProductionLine_IP); // } //} ////称重的S7设备 //var weightPLCDevice = Settings.WeightDevices; //if (weightPLCDevice.Count > 0) //{ // foreach (var item in weightPLCDevice) // { // new S7Helper(item.WeightDevice_IP, (short)item.WeightDevice_Rack, (short)item.WeightDevice_Slot); // Console.WriteLine("S7WeightDeviceHelper," + item.WeightDevice_Name); // } //} } /// <summary> @@ -111,7 +97,7 @@ private static void StartModbus() { // 所有的Modbus设备 var allPLCDevice = AppStart.Settings.Config.ProductionLines; // 运行时修改 config.json 无效 var allPLCDevice = Settings.ProductionLines; // 运行时修改 config.json 无效 if (allPLCDevice.Count > 0) { foreach (var item in allPLCDevice) { @@ -128,13 +114,13 @@ List<Task> tasks = new List<Task>(); // 轮询:出库单状态 tasks.Add(GetTask(OutboundCore.CheckOrderState)); tasks.Add(GetTask(Monitor.CheckOutboundOrder)); // 轮询:抽检单状态 tasks.Add(GetTask(CheckCore.CheckOrderState)); tasks.Add(GetTask(Monitor.CheckCheckOrder)); // 轮询:移库单状态 tasks.Add(GetTask(ShiftCore.CheckOrderState)); tasks.Add(GetTask(Monitor.CheckShiftOrder)); Task.WaitAll(tasks.ToArray()); } ServiceCore/CheckCore.cs
File was deleted ServiceCore/OfflineCore.cs
File was deleted ServiceCore/OutboundCore.cs
File was deleted ServiceCore/ShiftCore.cs
File was deleted ServiceCore/TaskCore.cs
File was deleted Services/AgvService.cs
File was deleted Services/DebugService.cs
File was deleted Services/MoboxService.cs
File was deleted Services/WmsService.cs
File was deleted api/AgvController.cs
File was renamed from Controllers/AgvController.cs @@ -1,13 +1,13 @@ using System.Web.Http; using HH.WCS.Mobox3.DSZSH.Services; using HH.WCS.Mobox3.DSZSH.core; using Newtonsoft.Json; using static HH.WCS.Mobox3.DSZSH.Dtos.Request.AgvRequest; using static HH.WCS.Mobox3.DSZSH.Dtos.Response.AgvResponse; using static HH.WCS.Mobox3.DSZSH.api.ApiModel; namespace HH.WCS.Mobox3.DSZSH.Controllers { namespace HH.WCS.Mobox3.DSZSH.api { /// <summary> /// 设备信息上报(HostToAGV上报、杭奥堆垛机、国自AGV) /// </summary> @@ -24,7 +24,7 @@ public ReturnResult AGVCallbackState(AgvTaskState model) { LogHelper.Info("NDC HostToAGV 任务状态回报:" + JsonConvert.SerializeObject(model), "HosttoagvTask"); return AgvService.OperateAgvTaskStatus(model); return WCSCore.OperateAgvTaskStatus(model); } /// <summary> @@ -35,7 +35,7 @@ [HttpPost] [Route("SafetyInteraction")] public ReturnResult SafetyInteraction(SafetyInteractionInfo model) { return AgvService.SafetyInteraction(model); return WCSCore.SafetyInteraction(model); } } } api/ApiHelper.cs
New file @@ -0,0 +1,1330 @@ using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using HH.WCS.Mobox3.DSZSH.models; using HH.WCS.Mobox3.DSZSH.util; using HH.WCS.Mobox3.DSZSH.wms; using Newtonsoft.Json; using SqlSugar; using Swashbuckle.Swagger; using static HH.WCS.Mobox3.DSZSH.api.ApiModel; using static HH.WCS.Mobox3.DSZSH.api.OtherModel; using static HH.WCS.Mobox3.DSZSH.Config; namespace HH.WCS.Mobox3.DSZSH.api { public class ApiHelper { /// <summary> /// 好运箱-满托下线入库(PDA) /// </summary> /// <param name="model"></param> /// <returns></returns> public static SimpleResult GoodpackOffline(GoodpackOfflineInfo model) { var taskName = TaskName.好运箱_满箱下线入库; // 用于生成任务类型、打印日志信息 var db = new SqlHelper<object>().GetInstance(); var info = ""; try { // 将PDA提供的物料编码与贴标机的信息比对 var cgDetail = db.Queryable<TN_CG_Detail>() .Where(d => d.S_ITEM_CODE == model.s_item_code && d.S_BATCH_NO == model.s_batch) // 指定:物料编码、批次号 .Where(d => d.N_ITEM_STATE == 1 && d.S_ITEM_STATE == "待检") // NOTE 冗余检查:物料状态应该为 1待检 .First(); if (cgDetail == null) { info = $"PDA扫码物料信息与贴标机传递的信息不一致:" + JsonConvert.SerializeObject(model); LogHelper.Info(info); return NewSimpleResult(1, info); } var startLoc = db.Queryable<TN_Location>() .Where(a => a.S_CODE == model.s_start_loc) // 指定:起点货位号 .Where(a => a.N_LOCK_STATE == 0 && a.S_LOCK_STATE == "无" && a.C_ENABLE == "Y") // 筛选:未上锁 .First(); if (startLoc == null) { info = $"起点位置 '{model.s_start_loc}' 不存在或不具备取货要求"; LogHelper.Info(info); return NewSimpleResult(3, info); } // 绑定货位和容器号 var locCntrRel = new TN_Loc_Container { S_LOC_CODE = model.s_start_loc, S_CNTR_CODE = cgDetail.S_CNTR_CODE, S_CNTR_TYPE = "好运箱", }; if (db.Insertable<TN_Loc_Container>(locCntrRel).ExecuteCommand() <= 0) { info = $"插入货位容器关系失败:" + JsonConvert.SerializeObject(locCntrRel); LogHelper.Info(info); return NewSimpleResult(4, info); } // TODO 满箱入库算法待优化 var endLoc = db.Queryable<TN_Location>() .Where(a => Settings.AreaMap[AreaName.满托存放区].Contains(a.S_AREA_CODE)) .Where(a => a.N_LOCK_STATE == 0 && a.S_LOCK_STATE == "无" && a.C_ENABLE == "Y") // 筛选:未上锁 .Where(a => a.N_CURRENT_NUM == 0) // 筛选:空货位 .OrderBy(l => l.N_LAYER) .OrderBy(l => l.S_AREA_CODE).First(); if (endLoc == null) { info = "满箱入库暂时没有合适的货位可以入库"; LogHelper.Info(info); return NewSimpleResult(4, info); } var cntId = locCntrRel.S_CNTR_CODE; var task = WCSHelper.BuildTask(startLoc, endLoc, cntId, taskName); LocationHelper.LockLoc(ref startLoc, 1); // 起点出库锁 LocationHelper.LockLoc(ref endLoc, 2); // 终点入库锁 using (var tran = db.Ado.UseTran()) { if (db.Updateable<TN_Location>(startLoc).UpdateColumns(it => new { it.N_LOCK_STATE, it.S_LOCK_STATE, it.S_LOCK_OP, it.T_MODIFY }).ExecuteCommand() <= 0) { tran.RollbackTran(); info = $"生成 {taskName} 失败,容器号 {cntId} ,起点 {startLoc.S_CODE} ,终点货位 {endLoc.S_CODE}"; LogHelper.Info(info); return NewSimpleResult(4, info); } if (db.Updateable<TN_Location>(endLoc).UpdateColumns(it => new { it.N_LOCK_STATE, it.S_LOCK_STATE, it.S_LOCK_OP, it.T_MODIFY }).ExecuteCommand() <= 0) { tran.RollbackTran(); info = $"生成 {taskName} 失败,容器号 {cntId} ,起点 {startLoc.S_CODE} ,终点货架 {endLoc.S_CODE}"; LogHelper.Info(info); return NewSimpleResult(4, info); } if (db.Insertable<TN_Task>(task).ExecuteCommand() <= 0) { tran.RollbackTran(); info = $"生成 {taskName} 失败,容器号 {cntId} ,起点 {startLoc.S_CODE} ,终点货架 {endLoc.S_CODE}"; LogHelper.Info(info); return NewSimpleResult(4, info); } tran.CommitTran(); info = $"生成 {taskName} 成功,容器号 {cntId} ,起点 {startLoc.S_CODE} ,终点货架 {endLoc.S_CODE}"; LogHelper.Info(info); return NewSimpleResult(0, info); } } catch (Exception ex) { info = $"发生了异常:{ex.Message}"; LogHelper.Info(info); return NewSimpleResult(1, info); } } ///// <summary> ///// 空托盘绑定(PDA) ///// </summary> ///// <param name="model"></param> ///// <returns></returns> //public static SimpleResult EmptyBindPallet(EmptyBindInfo model) { // var db = DbHelper.GetDbClient(); // try { // var loc = db.Queryable<TN_Location>() // .Where(ExprHelper.LocCode(model.LocCode)) // .Where(ExprHelper.LocBelongsToArea(AreaName.空托盘接驳区)) // .Where(ExprHelper.LocIsFree) // .Where(ExprHelper.LocIsEmpty).First(); // if (loc == null) { // return BuildSimpleResult(2, $"当前货位 '{model.LocCode}' 无法再绑定容器"); // } // var locCntrRel = db.Queryable<TN_Loc_Container>() // .Where(lc => lc.S_CNTR_CODE == model.LocCode).First(); // if (locCntrRel != null) { // return BuildSimpleResult(3, $"当前容器 '{model.CntrCode}' 已经与 '{locCntrRel.S_LOC_CODE}' 绑定"); // } // //loc.N_CURRENT_NUM = model.PalletCount; // locCntrRel = new TN_Loc_Container { // S_LOC_CODE = model.LocCode, // S_CNTR_CODE = model.CntrCode // }; // using (var tran = db.Ado.UseTran()) { // if (db.Insertable<TN_Loc_Container>(locCntrRel).ExecuteCommand() > 0 // && db.Updateable<TN_Location>(loc).UpdateColumns(it => it.N_CURRENT_NUM).ExecuteCommand() > 0) { // tran.CommitTran(); // return BuildSimpleResult(0, $"绑定容器 '{model.CntrCode}' 与货位 '{model.LocCode}' 成功"); // } // else { // tran.RollbackTran(); // return BuildSimpleResult(4, $"绑定容器 '{model.CntrCode}' 与货位 '{model.LocCode}' 失败"); // } // } // } // catch (Exception ex) { // return BuildSimpleEx(ex); // } //} ///// <summary> ///// 空箱绑定(PDA) ///// </summary> ///// <param name="model"></param> ///// <returns></returns> //public static SimpleResult EmptyBindGoodpack(EmptyBindInfo model) { // var db = DbHelper.GetDbClient(); // try { // var loc = db.Queryable<TN_Location>() // .Where(ExprHelper.LocCode(model.LocCode)) // .Where(ExprHelper.LocBelongsToArea(AreaName.空箱接驳区)) // .Where(ExprHelper.LocIsFree) // .Where(ExprHelper.LocIsEmpty).First(); // if (loc == null) { // return BuildSimpleResult(2, $"当前货位 '{model.LocCode}' 无法再绑定容器"); // } // var locCntrRel = db.Queryable<TN_Loc_Container>() // .Where(lc => lc.S_CNTR_CODE == model.LocCode).First(); // if (locCntrRel != null) { // return BuildSimpleResult(3, $"当前容器 '{model.CntrCode}' 已经与 '{locCntrRel.S_LOC_CODE}' 绑定"); // } // loc.N_CURRENT_NUM = 1; // 空箱绑定时容器数必然为 1 // locCntrRel = new TN_Loc_Container { // S_LOC_CODE = model.LocCode, // S_CNTR_CODE = model.CntrCode // }; // using (var tran = db.Ado.UseTran()) { // if (db.Insertable<TN_Loc_Container>(locCntrRel).ExecuteCommand() > 0 // && db.Updateable<TN_Location>(loc).UpdateColumns(it => it.N_CURRENT_NUM).ExecuteCommand() > 0) { // tran.CommitTran(); // return BuildSimpleResult(0, $"绑定容器 '{model.CntrCode}' 与货位 '{model.LocCode}' 成功"); // } // else { // tran.RollbackTran(); // return BuildSimpleResult(4, $"绑定容器 '{model.CntrCode}' 与货位 '{model.LocCode}' 失败"); // } // } // } // catch (Exception ex) { // return BuildSimpleEx(ex); // } //} /// <summary> /// 托盘-空托入库(PDA) /// </summary> /// <param name="model"></param> /// <returns></returns> public static SimpleResult EmptyInboundPallet(EmptyInboundInfo model) { var taskName = TaskName.托盘_空托入库; var db = new SqlHelper<object>().GetInstance(); var info = ""; try { var startLoc = db.Queryable<TN_Location>() .Where(a => a.S_CODE == model.StartLoc) // 指定:起点货位 .Where(a => a.N_LOCK_STATE == 0 && a.S_LOCK_STATE == "无" && a.C_ENABLE == "Y") // 筛选:未上锁 .Where(a => a.N_CURRENT_NUM == 1) .First(); if (startLoc == null) { return NewSimpleResult(2, $"起点位置 '{model.StartLoc}' 不存在或不具备取货要求"); } // 查看容器与起点货位是否绑定 var locCntrRel = db.Queryable<TN_Loc_Container>() .Where(c => c.S_LOC_CODE == model.StartLoc && c.S_CNTR_CODE == model.CntrCode) .First(); if (locCntrRel == null) { return NewSimpleResult(3, $"起点位置 '{model.StartLoc}' 没有绑定容器 '{model.CntrCode}'"); } // TODO 暂定选择最低层按区位顺序入库,后面待修改 var endLoc = db.Queryable<TN_Location>() .Where(a => Settings.AreaMap[AreaName.空托存放区].Contains(a.S_AREA_CODE)) .OrderBy(l => l.N_LAYER) .OrderBy(l => l.S_AREA_CODE).First(); if (endLoc == null) { return NewSimpleResult(4, $"暂时没有符合条件的终点放货位"); } var cntId = locCntrRel.S_CNTR_CODE; var task = WCSHelper.BuildTask(startLoc, endLoc, cntId, taskName); LocationHelper.LockLoc(ref startLoc, 1); // 起点出库锁 LocationHelper.LockLoc(ref endLoc, 2); // 终点入库锁 using (var tran = db.Ado.UseTran()) { if (db.Updateable<TN_Location>(startLoc).UpdateColumns(it => new { it.N_LOCK_STATE, it.S_LOCK_STATE, it.S_LOCK_OP, it.T_MODIFY }).ExecuteCommand() <= 0) { tran.RollbackTran(); return NewSimpleResult(500, $"生成 {taskName} 失败,容器号 {cntId} ,起点 {startLoc.S_CODE} ,终点货位 {endLoc.S_CODE}"); } if (db.Updateable<TN_Location>(endLoc).UpdateColumns(it => new { it.N_LOCK_STATE, it.S_LOCK_STATE, it.S_LOCK_OP, it.T_MODIFY }).ExecuteCommand() <= 0) { tran.RollbackTran(); return NewSimpleResult(500, $"生成 {taskName} 失败,容器号 {cntId} ,起点 {startLoc.S_CODE} ,终点货架 {endLoc.S_CODE}"); } if (db.Insertable<TN_Task>(task).ExecuteCommand() <= 0) { tran.RollbackTran(); return NewSimpleResult(500, $"生成 {taskName} 失败,容器号 {cntId} ,起点 {startLoc.S_CODE} ,终点货架 {endLoc.S_CODE}"); } tran.CommitTran(); return NewSimpleResult(0, $"生成 {taskName} 成功,容器号 {cntId} ,起点 {startLoc.S_CODE} ,终点货架 {endLoc.S_CODE}"); } } catch (Exception ex) { info = $"发生了异常:{ex.Message}"; LogHelper.Info(info); return NewSimpleResult(1, info); } } /// <summary> /// 好运箱-空箱入库(PDA) /// </summary> /// <returns></returns> public static SimpleResult EmptyInboundGoodpack(EmptyInboundInfo model) { var taskName = TaskName.好运箱_空箱入库; var db = new SqlHelper<object>().GetInstance(); var info = ""; try { var startLoc = db.Queryable<TN_Location>() .Where(a => a.S_CODE == model.StartLoc) .Where(a => a.N_LOCK_STATE == 0 && a.S_LOCK_STATE == "无" && a.C_ENABLE == "Y") // 筛选:未上锁 .Where(a => a.N_CURRENT_NUM == 1) // 筛选:有货货位 .First(); if (startLoc == null) { return NewSimpleResult(2, $"起点位置 '{model.StartLoc}' 不存在或不具备取货要求"); } // 查看容器与起点货位是否绑定 var locCntrRel = db.Queryable<TN_Loc_Container>() .Where(c => c.S_LOC_CODE == model.StartLoc && c.S_CNTR_CODE == model.CntrCode) .First(); if (locCntrRel == null) { return NewSimpleResult(3, $"起点位置 '{model.StartLoc}' 没有绑定容器 '{model.CntrCode}'"); } // TODO 暂定选择最低层按区位顺序入库,后面待修改 var endLoc = db.Queryable<TN_Location>() .Where(a => Settings.AreaMap[AreaName.空箱存放区].Contains(a.S_AREA_CODE)) .OrderBy(l => l.N_LAYER) .OrderBy(l => l.S_AREA_CODE).First(); if (endLoc == null) { return NewSimpleResult(4, $"暂时没有符合条件的终点放货位"); } var cntId = locCntrRel.S_CNTR_CODE; var task = WCSHelper.BuildTask(startLoc, endLoc, cntId, taskName); LocationHelper.LockLoc(ref startLoc, 1); // 起点出库锁 LocationHelper.LockLoc(ref endLoc, 2); // 终点入库锁 using (var tran = db.Ado.UseTran()) { if (db.Updateable<TN_Location>(startLoc).UpdateColumns(it => new { it.N_LOCK_STATE, it.S_LOCK_STATE, it.S_LOCK_OP, it.T_MODIFY }).ExecuteCommand() <= 0) { tran.RollbackTran(); return NewSimpleResult(500, $"生成 {taskName} 失败,容器号 {cntId} ,起点 {startLoc.S_CODE} ,终点货位 {endLoc.S_CODE}"); } if (db.Updateable<TN_Location>(endLoc).UpdateColumns(it => new { it.N_LOCK_STATE, it.S_LOCK_STATE, it.S_LOCK_OP, it.T_MODIFY }).ExecuteCommand() <= 0) { tran.RollbackTran(); return NewSimpleResult(500, $"生成 {taskName} 失败,容器号 {cntId} ,起点 {startLoc.S_CODE} ,终点货架 {endLoc.S_CODE}"); } if (db.Insertable<TN_Task>(task).ExecuteCommand() <= 0) { tran.RollbackTran(); return NewSimpleResult(500, $"生成 {taskName} 失败,容器号 {cntId} ,起点 {startLoc.S_CODE} ,终点货架 {endLoc.S_CODE}"); } tran.CommitTran(); return NewSimpleResult(0, $"生成 {taskName} 成功,容器号 {cntId} ,起点 {startLoc.S_CODE} ,终点货架 {endLoc.S_CODE}"); } } catch (Exception ex) { return BuildSimpleEx(ex); } } /// <summary> /// 托盘-空托上线(PDA) /// </summary> /// <param name="model"></param> /// <returns></returns> public static SimpleResult EmptyOnlinePallet(EmptyOnlinePalletInfo model) { var taskName = TaskName.托盘_空托上线; var db = new SqlHelper<object>().GetInstance(); var taskInfo = Settings.TaskMap[taskName]; var info = ""; try { // TODO 符合物料信息的货位 var startLoc = db.Queryable<TN_Location>() .Where(l => taskInfo.StartAreas.Contains(l.S_AREA_CODE)) .Where(a => a.N_LOCK_STATE == 0 && a.S_LOCK_STATE == "无" && a.C_ENABLE == "Y") // 筛选:未上锁 .Where(a => a.N_CURRENT_NUM == 1) // 筛选:有货货位 .First(); if (startLoc == null) { return NewSimpleResult(2, $"没有合适的起点位置"); } var locCntrRel = db.Queryable<TN_Loc_Container>().First( a => a.S_LOC_CODE == startLoc.S_CODE && a.S_CNTR_CODE == model.CntId); if (locCntrRel == null) { return NewSimpleResult(3, $"起点位置 '{startLoc.S_CODE}' 没有绑定容器 '{model.CntId}'"); } var endLoc = db.Queryable<TN_Location>() .Where(a => Settings.AreaMap[AreaName.包装区].Contains(a.S_AREA_CODE)) .Where(l => taskInfo.EndAreas.Contains(l.S_AREA_CODE)) .Where(a => a.N_LOCK_STATE == 0 && a.S_LOCK_STATE == "无" && a.C_ENABLE == "Y") // 筛选:未上锁 .Where(a => a.N_CURRENT_NUM == 0) // 筛选:空货位 .First(); if (endLoc == null) { return NewSimpleResult(4, $"终点位置 不存在或不具备放货要求"); } var cntId = locCntrRel.S_CNTR_CODE; var task = WCSHelper.BuildTask(startLoc, endLoc, cntId, taskName); LocationHelper.LockLoc(ref startLoc, 1); // 起点出库锁 LocationHelper.LockLoc(ref endLoc, 2); // 终点入库锁 using (var tran = db.Ado.UseTran()) { if (db.Updateable<TN_Location>(startLoc).UpdateColumns(it => new { it.N_LOCK_STATE, it.S_LOCK_STATE, it.S_LOCK_OP, it.T_MODIFY }).ExecuteCommand() <= 0) { tran.RollbackTran(); return NewSimpleResult(500, $"生成 {taskName} 失败,容器号 {cntId} ,起点 {startLoc.S_CODE} ,终点货位 {endLoc.S_CODE}"); } if (db.Updateable<TN_Location>(endLoc).UpdateColumns(it => new { it.N_LOCK_STATE, it.S_LOCK_STATE, it.S_LOCK_OP, it.T_MODIFY }).ExecuteCommand() <= 0) { tran.RollbackTran(); return NewSimpleResult(500, $"生成 {taskName} 失败,容器号 {cntId} ,起点 {startLoc.S_CODE} ,终点货架 {endLoc.S_CODE}"); } if (db.Insertable<TN_Task>(task).ExecuteCommand() <= 0) { tran.RollbackTran(); return NewSimpleResult(500, $"生成 {taskName} 失败,容器号 {cntId} ,起点 {startLoc.S_CODE} ,终点货架 {endLoc.S_CODE}"); } tran.CommitTran(); return NewSimpleResult(0, $"生成 {taskName} 成功,容器号 {cntId} ,起点 {startLoc.S_CODE} ,终点货架 {endLoc.S_CODE}"); } } catch (Exception ex) { return BuildSimpleEx(ex); } } /// <summary> /// 好运箱-空箱上线(PDA) /// </summary> /// <param name="model"></param> /// <returns></returns> public static SimpleResult EmptyOnlineGoodpack(EmptyOnlineGoodpackInfo model) { var taskName = TaskName.好运箱_空箱上线; var db = new SqlHelper<object>().GetInstance(); var taskInfo = Settings.TaskMap[taskName]; var info = ""; try { // TODO 符合物料信息的货位 var startLoc = db.Queryable<TN_Location>() .Where(l => taskInfo.StartAreas.Contains(l.S_AREA_CODE)) .Where(a => a.N_LOCK_STATE == 0 && a.S_LOCK_STATE == "无" && a.C_ENABLE == "Y") // 筛选:未上锁 .Where(a => a.N_CURRENT_NUM == 1).First(); if (startLoc == null) { return NewSimpleResult(2, $"没有合适的起点位置"); } var locCntrRel = db.Queryable<TN_Loc_Container>().First( a => a.S_LOC_CODE == startLoc.S_CODE && a.S_CNTR_CODE == model.CntId); if (locCntrRel == null) { return NewSimpleResult(3, $"起点位置 '{startLoc.S_CODE}' 没有绑定容器 '{model.CntId}'"); } var endLoc = db.Queryable<TN_Location>() .Where(a => Settings.AreaMap[AreaName.包装区].Contains(a.S_AREA_CODE)) .Where(l => taskInfo.EndAreas.Contains(l.S_AREA_CODE)) .Where(a => a.N_LOCK_STATE == 0 && a.S_LOCK_STATE == "无" && a.C_ENABLE == "Y") // 筛选:未上锁 .Where(a => a.N_CURRENT_NUM == 0) .First(); if (endLoc == null) { return NewSimpleResult(4, $"终点位置 不存在或不具备放货要求"); } var cntId = locCntrRel.S_CNTR_CODE; var task = WCSHelper.BuildTask(startLoc, endLoc, cntId, taskName); LocationHelper.LockLoc(ref startLoc, 1); // 起点出库锁 LocationHelper.LockLoc(ref endLoc, 2); // 终点入库锁 using (var tran = db.Ado.UseTran()) { if (db.Updateable<TN_Location>(startLoc).UpdateColumns(it => new { it.N_LOCK_STATE, it.S_LOCK_STATE, it.S_LOCK_OP, it.T_MODIFY }).ExecuteCommand() <= 0) { tran.RollbackTran(); return NewSimpleResult(500, $"生成 {taskName} 失败,容器号 {cntId} ,起点 {startLoc.S_CODE} ,终点货位 {endLoc.S_CODE}"); } if (db.Updateable<TN_Location>(endLoc).UpdateColumns(it => new { it.N_LOCK_STATE, it.S_LOCK_STATE, it.S_LOCK_OP, it.T_MODIFY }).ExecuteCommand() <= 0) { tran.RollbackTran(); return NewSimpleResult(500, $"生成 {taskName} 失败,容器号 {cntId} ,起点 {startLoc.S_CODE} ,终点货架 {endLoc.S_CODE}"); } if (db.Insertable<TN_Task>(task).ExecuteCommand() <= 0) { tran.RollbackTran(); return NewSimpleResult(500, $"生成 {taskName} 失败,容器号 {cntId} ,起点 {startLoc.S_CODE} ,终点货架 {endLoc.S_CODE}"); } tran.CommitTran(); return NewSimpleResult(0, $"生成 {taskName} 成功,容器号 {cntId} ,起点 {startLoc.S_CODE} ,终点货架 {endLoc.S_CODE}"); } } catch (Exception ex) { return BuildSimpleEx(ex); } } /// <summary> /// 创建抽检单 /// </summary> /// <param name="model"></param> /// <returns></returns> public static SimpleResult CreateCheckOrder(CreateCheckOrderInfo model) { var billName = "抽检单"; var db = new SqlHelper<object>().GetInstance(); var info = ""; try { var orderNo = GenerateOrderNo("抽检单号", "CN"); var order = new TN_Check_Order { S_NO = orderNo, S_ITEM_CODE = model.ItemCode, //S_ITEM_NAME = model.ItemName, S_BATCH_NO = model.BatchNo, N_COUNT = model.Qty, S_END_AREA = model.EndArea, }; var cgDetailList = SelectCgByTotalQty(model); if (cgDetailList.Count == 0) { return NewSimpleResult(3, "没有合适的物料可以抽检"); } var detailList = new List<TN_Check_Detail>(); foreach (var cgDetail in cgDetailList) { var detail = new TN_Check_Detail { S_NO = orderNo, S_ITEM_CODE = cgDetail.S_ITEM_CODE, S_BATCH_NO = cgDetail.S_BATCH_NO, S_CNTR_CODE = cgDetail.S_CNTR_CODE, S_END_AREA = model.EndArea, }; detailList.Add(detail); cgDetail.N_ITEM_STATE = 3; cgDetail.S_ITEM_STATE = "抽验中"; } using (var tran = db.Ado.UseTran()) { if (db.Insertable<TN_Check_Order>(order).ExecuteCommand() <= 0) { tran.RollbackTran(); info = $"生成{billName}失败:" + JsonConvert.SerializeObject(order); LogHelper.Info(info); return NewSimpleResult(2, info); } if (db.Insertable<TN_Outbound_Detail>(detailList).ExecuteCommand() <= 0) { tran.RollbackTran(); info = $"生成{billName}明细失败"; LogHelper.Info(info); return NewSimpleResult(4, info); } if (db.Updateable<TN_CG_Detail>(cgDetailList).UpdateColumns(it => new { it.N_ITEM_STATE, it.S_ITEM_STATE }).ExecuteCommand() <= 0) { tran.RollbackTran(); info = $"更新物料状态失败"; } tran.CommitTran(); } return NewSimpleResult(0, $"创建 抽检单 成功"); } catch (Exception ex) { return BuildSimpleEx(ex); } } /// <summary> /// 抽检-合格回库(PDA) /// </summary> /// <param name="model"></param> /// <returns></returns> public static SimpleResult QualifiedBack(QualifiedBackInfo model) { var taskName = TaskName.抽检_合格回库; var db = new SqlHelper<object>().GetInstance(); var info = ""; try { var cgDetail = db.Queryable<TN_CG_Detail>() .Where(d => d.S_ITEM_CODE == model.ItemCode && d.S_CNTR_CODE == model.CntrCode) .First(); if (cgDetail == null) { return NewSimpleResult(2, "没有找到待回库的抽检物料:" + JsonConvert.SerializeObject(model)); } var locCntrRel = db.Queryable<TN_Loc_Container>() .Where(c => c.S_CNTR_CODE == cgDetail.S_CNTR_CODE) .First(); //var startLoc = db.Queryable<TN_Location>() // .LeftJoin<TN_Loc_Container>((l, c) => l.S_CODE == c.S_LOC_CODE) // .Where((l, c) => c.S_CNTR_CODE == cgDetail.S_CNTR_CODE) // 指定容器号 // .Where(a => a.N_LOCK_STATE == 0 && a.S_LOCK_STATE == "无" && a.C_ENABLE == "Y") // 筛选:未上锁 // .First(); var startLoc = db.Queryable<TN_Location>() .Where(l => l.S_CODE == locCntrRel.S_LOC_CODE) .Where(a => a.N_LOCK_STATE == 0 && a.S_LOCK_STATE == "无" && a.C_ENABLE == "Y") // 筛选:未上锁 .First(); if (startLoc == null) { info = "没有找到合适的起点货位"; LogHelper.Info(info); return NewSimpleResult(0, info); } var endLoc = new TN_Location(); if (locCntrRel.S_CNTR_TYPE == "托盘") { endLoc = db.Queryable<TN_Location>() .Where(a => Settings.AreaMap[AreaName.满托存放区].Contains(a.S_AREA_CODE)) .Where(a => a.N_LOCK_STATE == 0 && a.S_LOCK_STATE == "无" && a.C_ENABLE == "Y") // 筛选:未上锁 .Where(a => a.N_CURRENT_NUM == 0) // 筛选:空货位 .First(); } else if (locCntrRel.S_CNTR_TYPE == "好运箱") { endLoc = db.Queryable<TN_Location>() .Where(a => Settings.AreaMap[AreaName.满箱存放区].Contains(a.S_AREA_CODE)) .Where(a => a.N_LOCK_STATE == 0 && a.S_LOCK_STATE == "无" && a.C_ENABLE == "Y") // 筛选:未上锁 .Where(a => a.N_CURRENT_NUM == 0) .First(); } else { return NewSimpleResult(2, $"托盘类型{locCntrRel.S_CNTR_TYPE}不合法:托盘号{locCntrRel.S_CNTR_CODE}"); } if (endLoc == null) { return NewSimpleResult(3, "查询:没有找到合适的终点货位"); } cgDetail.N_ITEM_STATE = 0; cgDetail.S_ITEM_STATE = "合格"; var cntId = locCntrRel.S_CNTR_CODE; var task = WCSHelper.BuildTask(startLoc, endLoc, cntId, taskName); LocationHelper.LockLoc(ref startLoc, 1); // 起点出库锁 LocationHelper.LockLoc(ref endLoc, 2); // 终点入库锁 using (var tran = db.Ado.UseTran()) { if (db.Updateable<TN_CG_Detail>(cgDetail).UpdateColumns(it => new { it.N_ITEM_STATE, it.S_ITEM_STATE }).ExecuteCommand() <= 0) { tran.RollbackTran(); info = "修改物料状态为合格 失败"; LogHelper.Info(info); return NewSimpleResult(4, info); } if (db.Updateable<TN_Location>(startLoc).UpdateColumns(it => new { it.N_LOCK_STATE, it.S_LOCK_STATE, it.S_LOCK_OP, it.T_MODIFY }).ExecuteCommand() <= 0) { tran.RollbackTran(); info = $"生成 {taskName} 失败,容器号 {cntId} ,起点 {startLoc.S_CODE} ,终点货位 {endLoc.S_CODE}"; LogHelper.Info(info); return NewSimpleResult(4, info); } if (db.Updateable<TN_Location>(endLoc).UpdateColumns(it => new { it.N_LOCK_STATE, it.S_LOCK_STATE, it.S_LOCK_OP, it.T_MODIFY }).ExecuteCommand() <= 0) { tran.RollbackTran(); info = $"生成 {taskName} 失败,容器号 {cntId} ,起点 {startLoc.S_CODE} ,终点货架 {endLoc.S_CODE}"; LogHelper.Info(info); return NewSimpleResult(4, info); } if (db.Insertable<TN_Task>(task).ExecuteCommand() <= 0) { tran.RollbackTran(); info = $"生成 {taskName} 失败,容器号 {cntId} ,起点 {startLoc.S_CODE} ,终点货架 {endLoc.S_CODE}"; LogHelper.Info(info); return NewSimpleResult(4, info); } tran.CommitTran(); return NewSimpleResult(0, $"生成 {taskName} 成功,容器号 {cntId} ,起点 {startLoc.S_CODE} ,终点货架 {endLoc.S_CODE}"); } } catch (Exception ex) { info = $"发生了异常:{ex.Message}"; LogHelper.Info(info); return NewSimpleResult(1, info); } } public static SimpleResult UnqualifiedShift(UnqualifiedShiftInfo model) { var taskName = TaskName.抽检_不合格移库; var db = new SqlHelper<object>().GetInstance(); var info = ""; try { var cgDetail = db.Queryable<TN_CG_Detail>() .Where(d => d.S_ITEM_CODE == model.ItemCode && d.S_CNTR_CODE == model.CntrCode) .First(); if (cgDetail == null) { return NewSimpleResult(2, "没有找到待回库的抽检物料"); } var locCntrRel = db.Queryable<TN_Loc_Container>() .Where(c => c.S_CNTR_CODE == cgDetail.S_CNTR_CODE) .First(); //var startLoc = db.Queryable<TN_Location>() // .LeftJoin<TN_Loc_Container>((l, c) => l.S_CODE == c.S_LOC_CODE) // .Where((l, c) => c.S_CNTR_CODE == cgDetail.S_CNTR_CODE) // 指定容器号 // .Where(a => a.N_LOCK_STATE == 0 && a.S_LOCK_STATE == "无" && a.C_ENABLE == "Y") // 筛选:未上锁 // .First(); var startLoc = db.Queryable<TN_Location>() .Where(l => l.S_CODE == locCntrRel.S_LOC_CODE) .Where(a => a.N_LOCK_STATE == 0 && a.S_LOCK_STATE == "无" && a.C_ENABLE == "Y") // 筛选:未上锁 .First(); if (startLoc == null) { info = "没有找到合适的起点货位"; LogHelper.Info(info); return NewSimpleResult(0, info); } var endLoc = db.Queryable<TN_Location>() .Where(l => l.S_AREA_CODE == model.EndArea) .Where(a => a.N_LOCK_STATE == 0 && a.S_LOCK_STATE == "无" && a.C_ENABLE == "Y") // 筛选:未上锁 .Where(a => a.N_CURRENT_NUM == 0).First(); if (endLoc == null) { return NewSimpleResult(3, "查询:没有找到合适的终点货位"); } cgDetail.N_ITEM_STATE = 2; cgDetail.S_ITEM_STATE = "不合格"; var cntId = locCntrRel.S_CNTR_CODE; var task = WCSHelper.BuildTask(startLoc, endLoc, cntId, taskName); LocationHelper.LockLoc(ref startLoc, 1); // 起点出库锁 LocationHelper.LockLoc(ref endLoc, 2); // 终点入库锁 using (var tran = db.Ado.UseTran()) { if (db.Updateable<TN_CG_Detail>(cgDetail).UpdateColumns(it => new { it.N_ITEM_STATE, it.S_ITEM_STATE }).ExecuteCommand() <= 0) { tran.RollbackTran(); info = "修改物料状态为合格 失败"; LogHelper.Info(info); return NewSimpleResult(4, info); } if (db.Updateable<TN_Location>(startLoc).UpdateColumns(it => new { it.N_LOCK_STATE, it.S_LOCK_STATE, it.S_LOCK_OP, it.T_MODIFY }).ExecuteCommand() <= 0) { tran.RollbackTran(); info = $"生成 {taskName} 失败,容器号 {cntId} ,起点 {startLoc.S_CODE} ,终点货位 {endLoc.S_CODE}"; LogHelper.Info(info); return NewSimpleResult(4, info); } if (db.Updateable<TN_Location>(endLoc).UpdateColumns(it => new { it.N_LOCK_STATE, it.S_LOCK_STATE, it.S_LOCK_OP, it.T_MODIFY }).ExecuteCommand() <= 0) { tran.RollbackTran(); info = $"生成 {taskName} 失败,容器号 {cntId} ,起点 {startLoc.S_CODE} ,终点货架 {endLoc.S_CODE}"; LogHelper.Info(info); return NewSimpleResult(4, info); } if (db.Insertable<TN_Task>(task).ExecuteCommand() <= 0) { tran.RollbackTran(); info = $"生成 {taskName} 失败,容器号 {cntId} ,起点 {startLoc.S_CODE} ,终点货架 {endLoc.S_CODE}"; LogHelper.Info(info); return NewSimpleResult(4, info); } tran.CommitTran(); return NewSimpleResult(0, $"生成 {taskName} 成功,容器号 {cntId} ,起点 {startLoc.S_CODE} ,终点货架 {endLoc.S_CODE}"); } } catch (Exception ex) { return BuildSimpleEx(ex); } } public static SimpleResult RestBack(RestBackInfo model) { var taskName = TaskName.尾箱回库; var db = new SqlHelper<object>().GetInstance(); var info = ""; try { var startLoc = db.Queryable<TN_Location>() .Where(l => l.S_CODE == model.StartLoc) .First(); var locCntrRel = db.Queryable<TN_Loc_Container>() .Where(c => c.S_LOC_CODE == model.StartLoc) .First(); if (locCntrRel == null) { return NewSimpleResult(2, $"起点货位 {model.StartLoc}"); } var endLoc = db.Queryable<TN_Location, TN_Loc_Container>((l, c) => l.S_CODE == c.S_LOC_CODE) .Where((l, c) => c.S_CNTR_TYPE == locCntrRel.S_CNTR_TYPE) .First(); if (endLoc == null) { return NewSimpleResult(3, $"不存在合适的终点货位可以回库"); } var cntId = locCntrRel.S_CNTR_CODE; var task = WCSHelper.BuildTask(startLoc, endLoc, cntId, taskName); LocationHelper.LockLoc(ref startLoc, 1); // 起点出库锁 LocationHelper.LockLoc(ref endLoc, 2); // 终点入库锁 using (var tran = db.Ado.UseTran()) { if (db.Updateable<TN_Location>(startLoc).UpdateColumns(it => new { it.N_LOCK_STATE, it.S_LOCK_STATE, it.S_LOCK_OP, it.T_MODIFY }).ExecuteCommand() <= 0) { tran.RollbackTran(); info = $"生成 {taskName} 失败,容器号 {cntId} ,起点 {startLoc.S_CODE} ,终点货位 {endLoc.S_CODE}"; LogHelper.Info(info); return NewSimpleResult(4, info); } if (db.Updateable<TN_Location>(endLoc).UpdateColumns(it => new { it.N_LOCK_STATE, it.S_LOCK_STATE, it.S_LOCK_OP, it.T_MODIFY }).ExecuteCommand() <= 0) { tran.RollbackTran(); info = $"生成 {taskName} 失败,容器号 {cntId} ,起点 {startLoc.S_CODE} ,终点货架 {endLoc.S_CODE}"; LogHelper.Info(info); return NewSimpleResult(4, info); } if (db.Insertable<TN_Task>(task).ExecuteCommand() <= 0) { tran.RollbackTran(); info = $"生成 {taskName} 失败,容器号 {cntId} ,起点 {startLoc.S_CODE} ,终点货架 {endLoc.S_CODE}"; LogHelper.Info(info); return NewSimpleResult(4, info); } tran.CommitTran(); info = $"生成 {taskName} 成功,容器号 {cntId} ,起点 {startLoc.S_CODE} ,终点货架 {endLoc.S_CODE}"; LogHelper.Info(info); return NewSimpleResult(0, info); } } catch (Exception ex) { return BuildSimpleEx(ex); } } public static List<TN_CG_Detail> SelectCgByTotalQty(CreateCheckOrderInfo model) { var db = new SqlHelper<object>().GetInstance(); var result = new List<TN_CG_Detail>(); var targetNum = model.Qty; try { var targetCg = db.Queryable<TN_CG_Detail>().Where(a => a.S_ITEM_CODE == model.ItemCode && a.N_ITEM_NUM > targetNum). OrderBy(a => a.N_ITEM_NUM, OrderByType.Asc).First(); if (targetCg != null) //刚好有一行满足条件 { result.Add(targetCg); return result; } var sortedMaterials = new List<TN_CG_Detail>(); sortedMaterials = db.Queryable<TN_CG_Detail, TN_Loc_Container>((d, c) => d.S_CNTR_CODE == c.S_CNTR_CODE) .Where(d => d.S_ITEM_CODE == model.ItemCode && d.S_BATCH_NO == model.BatchNo && d.N_ITEM_NUM > 0) .Where((d, c) => c.S_CNTR_TYPE == model.CntrType) .Where(d => d.N_ITEM_STATE == 1 && d.S_ITEM_STATE == "待检") .OrderBy(d => d.N_ITEM_NUM, OrderByType.Desc) .OrderBy(d => d.N_ITEM_STATE, OrderByType.Asc).ToList(); if (sortedMaterials.Count == 0) //没有满足条件的 { return result; } int countNum = 0; foreach (var mat in sortedMaterials) { countNum += mat.N_ITEM_NUM; result.Add(mat); if (countNum >= targetNum) { break; } } if (result.Sum(a => a.N_ITEM_NUM) >= targetNum) { return result; } else { result.Clear(); return result; } } catch (Exception ex) { throw ex; } } /// <summary> /// 成品胶出库(WMS) /// </summary> /// <remarks> /// WMS提供出库的物料类型与数量,调用接口由WCS生成具体的出库任务,然后WCS后台轮询处理 /// </remarks> /// <param name="model"></param> /// <returns></returns> public static SimpleResult FinishedOutbound(FinishedOutboundInfo model) { var db = new SqlHelper<object>().GetInstance(); var orderNo = GenerateOrderNo("出库单号", "ON"); var info = ""; try { if (string.IsNullOrEmpty(orderNo)) { info = "出库单号不能为空"; LogHelper.Info(info); return NewSimpleResult(2, info); } var cgDetailList = SelectCgByTotalQty(model); if (cgDetailList.Count == 0) { info = "没有合适的物料可以出库"; LogHelper.Info(info); return NewSimpleResult(3, info); } var order = new TN_Outbound_Order { S_NO = orderNo, S_ITEM_CODE = model.ItemCode, S_BATCH = model.BatchNo, N_END_NUM = model.Qty, //F_OUT_QTY = cgDetailList.Sum(a => a.N_QTY), S_END_AREA = model.EndArea }; var detailList = new List<TN_Outbound_Detail>(); foreach (var cgDetail in cgDetailList) { var detail = new TN_Outbound_Detail { S_OO_NO = orderNo, S_ITEM_CODE = cgDetail.S_ITEM_CODE, S_BATCH_NO = cgDetail.S_BATCH_NO, S_CNTR_CODE = cgDetail.S_CNTR_CODE, N_COUNT = cgDetail.N_ITEM_NUM, S_END_AREA = model.EndArea }; detailList.Add(detail); } using (var tran = db.Ado.UseTran()) { if (db.Insertable<TN_Outbound_Order>(order).ExecuteCommand() <= 0) { tran.RollbackTran(); info = "生成出库单失败:" + JsonConvert.SerializeObject(order); LogHelper.Info(info); return NewSimpleResult(2, info); } if (db.Insertable<TN_Outbound_Detail>(detailList).ExecuteCommand() <= 0) { tran.RollbackTran(); info = "生成出库单明细失败"; LogHelper.Info(info); return NewSimpleResult(4, info); } tran.CommitTran(); } return NewSimpleResult(0, "生成出库单成功"); } catch (Exception ex) { return BuildSimpleEx(ex); } } /// <summary> /// 成品胶强制出库(WMS) /// </summary> /// <returns></returns> public static SimpleResult FinishedOutboundForce(FinishedOutboundInfo model) { var db = new SqlHelper<object>().GetInstance(); var orderNo = GenerateOrderNo("出库单号", "ON"); var info = ""; try { if (string.IsNullOrEmpty(orderNo)) { return NewSimpleResult(2, "出库单号不能为空"); } using (var tran = db.Ado.UseTran()) { var cgDetailList = SelectCgByTotalQty(model); if (cgDetailList.Count == 0) { return NewSimpleResult(3, "没有合适的物料可以出库"); } foreach (var cgDetail in cgDetailList) { var detail = new TN_Outbound_Detail { S_OO_NO = orderNo, S_ITEM_CODE = cgDetail.S_ITEM_CODE, S_BATCH_NO = cgDetail.S_BATCH_NO, S_CNTR_CODE = cgDetail.S_CNTR_CODE, S_END_AREA = model.EndArea }; if (db.Insertable<TN_Outbound_Detail>(detail).ExecuteCommand() <= 0) { tran.RollbackTran(); return NewSimpleResult(4, "生成出库单明细失败:" + JsonConvert.SerializeObject(detail)); } } var order = new TN_Outbound_Order { S_NO = orderNo, S_ITEM_CODE = model.ItemCode, S_BATCH = model.BatchNo, N_END_NUM = model.Qty, //F_OUT_QTY = cgDetailList.Sum(a => a.N_QTY), S_END_AREA = model.EndArea }; if (db.Insertable<TN_Outbound_Order>(order).ExecuteCommand() <= 0) { tran.RollbackTran(); return NewSimpleResult(5, "生成出库单失败:" + JsonConvert.SerializeObject(order)); } tran.CommitTran(); } return NewSimpleResult(0, "生成出库单成功"); } catch (Exception ex) { return BuildSimpleEx(ex); } } public static List<TN_CG_Detail> SelectCgByTotalQty(FinishedOutboundInfo model) { var db = new SqlHelper<object>().GetInstance(); var result = new List<TN_CG_Detail>(); var targetNum = model.Qty; var info = ""; try { var targetCg = db.Queryable<TN_CG_Detail>().Where(a => a.S_ITEM_CODE == model.ItemCode && a.N_ITEM_NUM > targetNum). OrderBy(a => a.N_ITEM_NUM, OrderByType.Asc).First(); if (targetCg != null) //刚好有一行满足条件 { result.Add(targetCg); return result; } // NOTE 根据总量选detail时,是否需要考虑货位的高低? var sortedMaterials = new List<TN_CG_Detail>(); if (model.ForcedOut) { sortedMaterials = db.Queryable<TN_CG_Detail, TN_Loc_Container>((d, c) => d.S_CNTR_CODE == c.S_CNTR_CODE) .Where(d => d.S_ITEM_CODE == model.ItemCode && d.S_BATCH_NO == model.BatchNo && d.N_ITEM_NUM > 0) .Where((d, c) => c.S_CNTR_TYPE == model.CntrType) .Where(d => d.N_ITEM_STATE == 0 && d.S_ITEM_STATE == "合格" || d.N_ITEM_STATE == 1 && d.S_ITEM_STATE == "待检") .OrderBy(d => d.N_ITEM_NUM, OrderByType.Desc) .OrderBy(d => d.N_ITEM_STATE, OrderByType.Asc).ToList(); } else { sortedMaterials = db.Queryable<TN_CG_Detail, TN_Loc_Container>((d, c) => d.S_CNTR_CODE == c.S_CNTR_CODE) .Where(d => d.S_ITEM_CODE == model.ItemCode && d.S_BATCH_NO == model.BatchNo && d.N_ITEM_NUM > 0) .Where((d, c) => c.S_CNTR_TYPE == model.CntrType) .Where(d => d.N_ITEM_STATE == 0 && d.S_ITEM_STATE == "合格") .OrderBy(d => d.N_ITEM_NUM, OrderByType.Desc) .OrderBy(d => d.N_ITEM_STATE, OrderByType.Asc).ToList(); } if (sortedMaterials.Count == 0) //没有满足条件的 { return result; } int countNum = 0; foreach (var mat in sortedMaterials) { countNum += mat.N_ITEM_NUM; result.Add(mat); if (countNum >= targetNum) { break; } } if (result.Sum(a => a.N_ITEM_NUM) >= targetNum) { return result; } else { result.Clear(); return result; } } catch (Exception ex) { info = $"发生了异常:{ex.Message}"; LogHelper.Info(info); return result; } } /// <summary> /// 移库-创建移库任务(WMS) /// </summary> /// <param name="model"></param> /// <returns></returns> public static SimpleResult CreateShiftOrder(CreateShiftOrderInfo model) { var billName = "抽检单"; var db = new SqlHelper<object>().GetInstance(); var info = ""; try { var orderNo = GenerateOrderNo("抽检单号", "CN"); var order = new TN_Check_Order { S_NO = orderNo, S_ITEM_CODE = model.ItemCode, //S_ITEM_NAME = model.ItemName, S_BATCH_NO = model.BatchNo, //N_COUNT = model.Qty, S_END_AREA = model.EndArea, }; var cgDetailList = SelectShiftItem(model); if (cgDetailList.Count == 0) { return NewSimpleResult(3, "没有符合要求的物料需要移库"); } var detailList = new List<TN_Check_Detail>(); foreach (var cgDetail in cgDetailList) { var detail = new TN_Check_Detail { S_NO = orderNo, S_ITEM_CODE = cgDetail.S_ITEM_CODE, S_BATCH_NO = cgDetail.S_BATCH_NO, S_CNTR_CODE = cgDetail.S_CNTR_CODE, S_END_AREA = model.EndArea, }; detailList.Add(detail); cgDetail.N_ITEM_STATE = 3; cgDetail.S_ITEM_STATE = "抽验中"; } using (var tran = db.Ado.UseTran()) { if (db.Insertable<TN_Check_Order>(order).ExecuteCommand() <= 0) { tran.RollbackTran(); info = $"生成{billName}失败:" + JsonConvert.SerializeObject(order); LogHelper.Info(info); return NewSimpleResult(2, info); } if (db.Insertable<TN_Outbound_Detail>(detailList).ExecuteCommand() <= 0) { tran.RollbackTran(); info = $"生成{billName}明细失败"; LogHelper.Info(info); return NewSimpleResult(4, info); } if (db.Updateable<TN_CG_Detail>(cgDetailList).UpdateColumns(it => new { it.N_ITEM_STATE, it.S_ITEM_STATE }).ExecuteCommand() <= 0) { tran.RollbackTran(); info = $"更新物料状态失败"; } tran.CommitTran(); } return NewSimpleResult(0, $"创建 抽检单 成功"); } catch (Exception ex) { return BuildSimpleEx(ex); } } public static List<TN_CG_Detail> SelectShiftItem(CreateShiftOrderInfo model) { var db = new SqlHelper<object>().GetInstance(); var result = new List<TN_CG_Detail>(); var info = ""; try { var targetItemList = db.Queryable<TN_CG_Detail>() .Where(a => a.S_ITEM_CODE == model.ItemCode) .Where(a => a.S_BATCH_NO == model.BatchNo) .Where(a => a.N_ITEM_STATE != 3 && a.S_ITEM_CODE != "抽检中") .OrderBy(a => a.N_ITEM_NUM, OrderByType.Asc) .ToList(); return targetItemList; } catch (Exception ex) { info = $"发生了异常:{ex.Message}"; LogHelper.Info(info); return result; } } private static string GenerateOrderNo(string snType, string prefix) { var id = SYSHelper.GetSerialNumber(snType, prefix); var date = DateTime.Now.ToString("yyMMdd"); return $"ON{date}{id.ToString().PadLeft(4, '0')}"; } /// <summary> /// 博实物料信息下发同步 /// </summary> /// <param name="model"></param> /// <returns></returns> public static WmsResult CgInfoSync(CgInfoSyncInfo model) { var db = new SqlHelper<object>().GetInstance(); var random = new Random(); try { var detail = new TN_CG_Detail { S_ITEM_CODE = model.ItemCode, S_ITEM_NAME = model.ItemName, S_CNTR_CODE = Guid.NewGuid().ToString("D"), // NOTE 容器号:目前随机(后期可能会指定,或者PDA绑定时再填入) S_BATCH_NO = model.BatchNo, S_STANDARD = model.Standard, S_NET_WEIGHT = model.NetWeight, S_QUALITY_GRADE = model.QualityGrade, //N_PRODUCT_LINE = random.Next(0, 3), // NOTE 产线号:目前随机(后期可能会指定,或者PDA绑定时再填入) }; // 货位容器绑定的逻辑,在好运箱下线PDA的流程中操作 //var locCntrRel = new TN_Loc_Container { // //S_LOC_CODE = Settings.Config.ProductionLines[detail.N_PRODUCT_LINE].OffLoc[0], // 好运箱的位置是操作区,不是产线 // S_CNTR_CODE = detail.S_CNTR_CODE, // S_CNTR_TYPE = "好运箱", // 贴标机只针对好运箱 //}; //using (var tran = db.Ado.UseTran()) { // if (db.Insertable<TN_CG_Detail>(detail).ExecuteCommand() <= 0 // && db.Insertable<TN_Loc_Container>(detail).ExecuteCommand() <= 0) { // tran.RollbackTran(); // return MesResultBuilder(2, "插入物料信息失败:" + JsonConvert.SerializeObject(detail)); // } // tran.CommitTran(); //} if (db.Insertable<TN_CG_Detail>(detail).ExecuteCommand() <= 0) { return MesResultBuilder(2, "插入物料信息失败:" + JsonConvert.SerializeObject(detail)); } return MesResultBuilder(0, "插入物料信息成功"); } catch (Exception ex) { return MesResultBuilder(1, ex.Message); } } } } api/ApiModel.cs
New file @@ -0,0 +1,573 @@ using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using Newtonsoft.Json; namespace HH.WCS.Mobox3.DSZSH.api { public class ApiModel { /// <summary> /// Mobox 接口返回数据类 /// </summary> public class SimpleResult { public int resultCode { get; set; } public string resultMsg { get; set; } public List<object> result { get; set; } = new List<object>(); } /// <summary> /// 构建 <see cref="SimpleResult"/> 返回值 /// </summary> /// <param name="code"></param> /// <param name="message"></param> /// <returns></returns> public static SimpleResult NewSimpleResult(int code, string message) { return new SimpleResult { resultCode = code, resultMsg = message }; } /// <summary> /// 构建 <see cref="SimpleResult"/> 异常返回值,选择打印异常日志信息(默认打印) /// </summary> /// <param name="ex"></param> /// <param name="exCode"></param> /// <param name="pringLog"></param> /// <returns></returns> public static SimpleResult BuildSimpleEx(Exception ex, int exCode = 1, bool pringLog = true) { if (pringLog) { LogHelper.InfoEx(ex); } return new SimpleResult { resultCode = exCode, resultMsg = ex.Message }; } /// <summary> /// HostToAGV 上报任务状态 /// </summary> public class AgvTaskState { /// <summary> /// AGV 回报状态号 /// </summary> public int state { get; set; } /// <summary> /// 任务号 /// </summary> public string task_no { get; set; } /// <summary> /// AGV 车号 /// </summary> public string forklift_no { get; set; } /// <summary> /// 安全门编号 /// </summary> public string lock_no { get; set; } /// <summary> /// 附加信息 /// </summary> public string ext_data { get; set; } } public class SafetyInteractionInfo { public int station_id { get; set; } /// <summary> /// 请求上线/下线的的站台库位名称,例如work6、work8 /// </summary> public string station_name { get; set; } /// <summary> /// 请求码 /// </summary> public string apply_code { get; set; } public string task_no { set; get; } } /// <summary> /// 返回给 HostToAgv /// </summary> public class ReturnResult { public int ResultCode { get; set; } public string ResultMsg { get; set; } } public class orderStatusReportParme { /// <summary> /// 订单ID /// </summary> public int orderID { get; set; } /// <summary> /// 订单名 /// </summary> public string orderName { get; set; } /// <summary> /// 订单状态 /// </summary> public string orderStatus { get; set; } /// <summary> /// agv车号列表 /// </summary> public string agvIDList { get; set; } /// <summary> /// 优先级 /// </summary> public string priority { get; set; } /// <summary> /// 订单当前的目的地 /// </summary> public string currentDes { get; set; } /// <summary> /// 当前指令 /// </summary> public string currentCmd { get; set; } /// <summary> /// 错误码 /// </summary> public int errorCode { get; set; } /// <summary> /// 订单的截至时间 /// </summary> public string deadLine { get; set; } /// <summary> /// 订单的创建时间 /// </summary> public string createdTime { get; set; } /// <summary> /// 额外信息1 /// </summary> public string extraInfo1 { get; set; } /// <summary> /// 额外信息2 /// </summary> public string extraInfo2 { get; set; } } /// <summary> /// 返回给GZ /// </summary> public class GzResult { public int resultCode { get; set; } public string msg { get; set; } public int orderID { get; set; } } } public class OtherModel { #region PDA 数据 /// <summary> /// 好运箱-满托下线入库(PDA)数据类 /// </summary> public class GoodpackOfflineInfo { /// <summary> /// 物料编码 /// </summary> public string s_item_code { get; set; } ///// <summary> ///// 物料名称 ///// </summary> //[JsonProperty("item_name")] //public string ItemName { get; set; } /// <summary> /// 批次号 /// </summary> public string s_batch { get; set; } /// <summary> /// 物料规格 /// </summary> public string s_spec { get; set; } /// <summary> /// 数量 /// </summary> public int n_num { get; set; } /// <summary> /// 起点货位信息 /// </summary> public string s_start_loc { get; set; } } /// <summary> /// 空托/空箱入库绑定(PDA)数据类 /// </summary> public class EmptyBindInfo { /// <summary> /// 容器编码 /// </summary> [JsonProperty("s_cntr_code")] public string CntrCode { get; set; } /// <summary> /// 容器类型 /// </summary> [JsonProperty("s_cntr_type")] public string CntrType { get; set; } ///// <summary> ///// 托盘数量(仅当容器类型为托盘时使用) ///// </summary> //[JsonProperty("pallet_count", NullValueHandling = NullValueHandling.Ignore)] //public int PalletCount { get; set; } /// <summary> /// 货位编码 /// </summary> [JsonProperty("s_loc_code")] public string LocCode { get; set; } } /// <summary> /// 空托绑定 /// </summary> public class EmptyBindPalletInfo { /// <summary> /// 容器编码 /// </summary> public string CntrCode { get; set; } /// <summary> /// 托盘数量 /// </summary> public int PalletCount { get; set; } /// <summary> /// 货位编码 /// </summary> public string LocCode { get; set; } } /// <summary> /// 空箱绑定 /// </summary> public class EmptyBindGoodpackInfo { /// <summary> /// 容器编码 /// </summary> public string CntrCode { get; set; } /// <summary> /// 货位编码 /// </summary> public string LocCode { get; set; } } /// <summary> /// 空托/空箱入库(PDA)数据类 /// </summary> public class EmptyInboundInfo { /// <summary> /// 容器编码 /// </summary> [JsonProperty("cntr_code")] public string CntrCode { get; set; } /// <summary> /// 容器类型 /// </summary> [JsonProperty("cntr_type")] public string CntrType { get; set; } /// <summary> /// 终点库区编码 /// </summary> [JsonProperty("end_area")] public string EndArea { get; set; } /// <summary> /// 起点货位 /// </summary> [JsonProperty("start_loc")] public string StartLoc { get; set; } } public class EmptyInboundDetailInfo { } //public class EmptyOnlineInfo { // public string ItemCode { get; set; } // public string ItemName { get; set; } // public string PatchNo { get; set; } // public string EndLoc { get; set; } //} public class EmptyOnlinePalletInfo { /// <summary> /// 物料编码 /// </summary> [JsonProperty("item_code")] public string ItemCode { get; set; } ///// <summary> ///// 物料名称 ///// </summary> // //[JsonProperty("item_name")] //public string ItemName { get; set; } /// <summary> /// 批次号 /// </summary> [JsonProperty("batch_no")] public string BatchNo { get; set; } /// <summary> /// 物料规格 /// </summary> [JsonProperty("spe")] public string Spe { get; set; } /// <summary> /// 容器编码 /// </summary> [JsonProperty("cnt_id")] public string CntId { get; set; } // 容器类型 = 托盘 } public class EmptyOnlineGoodpackInfo { // 容器类型 = 好运箱 /// <summary> /// 容器编码 /// </summary> [JsonProperty("cnt_id")] public string CntId { get; set; } } /// <summary> /// 抽检-创建抽检单(WMS)数据类 /// </summary> public class CreateCheckOrderInfo { /// <summary> /// 物料编码 /// </summary> [JsonProperty("item_code")] public string ItemCode { get; set; } ///// <summary> ///// 物料名称 ///// </summary> // //[JsonProperty("item_name")] //public string ItemName { get; set; } /// <summary> /// 物料规格 /// </summary> [JsonProperty("spe")] public string Spe { get; set; } /// <summary> /// 批次号 /// </summary> [JsonProperty("batch_no")] public string BatchNo { get; set; } /// <summary> /// 需出库数量 /// </summary> [JsonProperty("qty")] public int Qty { get; set; } /// <summary> /// 容器类型 /// </summary> [JsonProperty("cntr_type")] public string CntrType { get; set; } /// <summary> /// 出库终点货区 /// </summary> [JsonProperty("end_area")] public string EndArea { get; set; } } /// <summary> /// 抽检-合格回库(PDA) 数据类 /// </summary> public class QualifiedBackInfo { /// <summary> /// 物料编码 /// </summary> [JsonProperty("item_code")] public string ItemCode { get; set; } /// <summary> /// 容器编码 /// </summary> [JsonProperty("cntr_code")] public string CntrCode { get; set; } } public class UnqualifiedShiftInfo : QualifiedBackInfo { /// <summary> /// 不合格移库终点库区 /// </summary> [JsonProperty("end_area")] public string EndArea { get; set; } } public class CheckShiftInfo : UnqualifiedShiftInfo { public bool Qualified { get; set; } } #endregion #region WMS 数据 /// <summary> /// 成品胶出库(PDA) /// </summary> public class FinishedOutboundInfo { /// <summary> /// 物料编码 /// </summary> [JsonProperty("item_code")] public string ItemCode { get; set; } ///// <summary> ///// 物料名称 ///// </summary> //[JsonProperty("item_name")] //public string ItemName { get; set; } /// <summary> /// 物料规格 /// </summary> [JsonProperty("spe")] public string Spe { get; set; } /// <summary> /// 批次号 /// </summary> [JsonProperty("batch_no")] public string BatchNo { get; set; } /// <summary> /// 需出库数量 /// </summary> [JsonProperty("qty")] public int Qty { get; set; } /// <summary> /// 容器类型 /// </summary> [JsonProperty("cntr_type")] public string CntrType { get; set; } /// <summary> /// 出库终点货区 /// </summary> [JsonProperty("end_area")] public string EndArea { get; set; } /// <summary> /// 是否强制出库 /// </summary> [JsonProperty("force_out")] public bool ForcedOut { get; set; } } /// <summary> /// 移库-创建移库任务数据类 /// </summary> public class CreateShiftOrderInfo { /// <summary> /// 物料编码 /// </summary> [JsonProperty("item_code")] public string ItemCode { get; set; } ///// <summary> ///// 物料名称 ///// </summary> // //[JsonProperty("item_name")] //public string ItemName { get; set; } /// <summary> /// 批次号 /// </summary> [JsonProperty("batch_no")] public string BatchNo { get; set; } /// <summary> /// 移库终点货区 /// </summary> [JsonProperty("end_area")] public string EndArea { get; set; } } /// <summary> /// 余料尾箱回库(PDA)数据类 /// </summary> public class RestBackInfo { /// <summary> /// 起点货位 /// </summary> [JsonProperty("start_loc")] public string StartLoc { get; set; } } #endregion /// <summary> /// 物料信息下发同步 数据类 /// </summary> public class CgInfoSyncInfo { /// <summary> /// 物料名称 /// </summary> [JsonProperty("itemName")] public string ItemName { get; set; } /// <summary> /// 产品牌号 /// </summary> [JsonProperty("itemCode")] public string ItemCode { get; set; } /// <summary> /// 批次号 /// </summary> [JsonProperty("batchNo")] public string BatchNo { get; set; } /// <summary> /// 执行标准 /// </summary> [JsonProperty("standard")] public string Standard { get; set; } /// <summary> /// 净含量 /// </summary> [JsonProperty("netWeight")] public string NetWeight { get; set; } /// <summary> /// 质量等级 /// </summary> [JsonProperty("qualityGrade")] public string QualityGrade { get; set; } } /// <summary> /// MES API 响应结果类 /// </summary> public class WmsResult { /// <summary> /// 接口调用结果 1-成功 0-失败 /// </summary> [JsonProperty("result")] public int Result { get; set; } /// <summary> /// 是否成功 True-成功,False:失败 /// </summary> [JsonProperty("success")] public bool Success { get; set; } /// <summary> /// 这里是string类型,对结果的描述 /// </summary> [JsonProperty("data")] public string Data { get; set; } } public static WmsResult MesResultBuilder(int code, string message = "", bool printLog = true) { if (printLog && string.IsNullOrEmpty(message)) { LogHelper.Info(message); } return new WmsResult { Result = code, Success = code == 0, // 仅当code=0时,success=true Data = message, }; } } } api/DebugController.cs
New file @@ -0,0 +1,216 @@ using System; using System.Collections.Generic; using System.Runtime.ConstrainedExecution; using System.Web.Http; using HH.WCS.Mobox3.DSZSH.models; using HH.WCS.Mobox3.DSZSH.util; using Newtonsoft.Json; using static HH.WCS.Mobox3.DSZSH.api.ApiModel; namespace HH.WCS.Mobox3.DSZSH.api { /// <summary> /// 测试用:如果项目中要和设备对接,前期设备无法测试,用接口模拟 /// </summary> [RoutePrefix("api")] public class DebugController : ApiController { /// <summary> /// 模拟 AGV 多次回报任务状态 /// </summary> /// <param name="model">容器号</param> /// <returns></returns> [HttpPost] [Route("AgvSeriesReports")] public ReturnResults AgvSeriesReports(UpdateTaskState model) { return new ReturnResults(); } /// <summary> /// 初始化数据库 /// </summary> /// <returns></returns> [HttpPost] [Route("CreateDatabase")] public string CreateDatabase(CoverInfo model) { var cover = model.IsCover; try { var db = new SqlHelper<object>().GetInstance(); var entityTypes = new Type[] { //typeof(TN_CAR_IN), //typeof(TN_CG_Detail), //typeof(TN_Container), //typeof(TN_Loc_Container), //typeof(TN_Location), //typeof(TN_Task), //typeof(TN_Task_Action), //typeof(SysHelper.OI_SYS_MAXID), //typeof(TN_Inbound_Order), typeof(TN_Check_Detail), //typeof(TN_Check_Order), //typeof(TN_CNTR_ITEM), //typeof(TN_Outbound_Detail), //typeof(TN_Outbound_Order), //typeof(TN_Shift_Order), //typeof(TN_Shift_Detail) }; using (var tran = db.Ado.UseTran()) { if (cover) { // 删除所有表(按依赖关系倒序) //var tables = db.DbMaintenance.GetTableInfoList(); //foreach (var table in tables.OrderByDescending(t => t.Name)) { // db.DbMaintenance.DropTable(table.Name); //} // 创建新表 db.CodeFirst.InitTables(entityTypes); //db.CodeFirst.BackupTable().InitTables(entityTypes); } else { db.CodeFirst.InitTables(entityTypes); } tran.CommitTran(); } } catch (Exception ex) { LogHelper.Info($"发生了异常"); return "初始化数据库错误" + ex.Message; } return "成功"; } /// <summary> /// DEBUG:插入货位、容器、货品信息 /// </summary> /// <returns></returns> [HttpPost] [Route("InsertLocCntrCg")] public string InsertLocCntrCg(LocCntrCg locCntrCg) { var db = new SqlHelper<object>().GetInstance(); try { using (var tran = db.UseTran()) { LogHelper.Info("LogCntrCg:" + JsonConvert.SerializeObject(locCntrCg)); if (string.IsNullOrEmpty(locCntrCg.LocCode)) return ""; var loc = db.Queryable<TN_Location>().First(a => a.S_CODE == locCntrCg.LocCode); if (loc == null) { var newLoc = new TN_Location { S_CODE = locCntrCg.LocCode, S_AREA_CODE = locCntrCg.LocArea ?? "" }; if (db.Insertable<TN_Location>(newLoc).ExecuteCommand() <= 0) { tran.RollbackTran(); LogHelper.Info($"插入位置{locCntrCg.LocCode}失败"); return "插入失败"; } loc = newLoc; } if (string.IsNullOrEmpty(locCntrCg.CntrCode)) { LogHelper.Info("容器号为空,不再读取后面的数据"); return ""; } var locCntrRel = db.Queryable<TN_Loc_Container>().First(a => a.S_LOC_CODE == locCntrCg.LocCode && a.S_CNTR_CODE == locCntrCg.CntrCode); if (locCntrRel == null) { var newLocCntrRel = new TN_Loc_Container { S_LOC_CODE = locCntrCg.LocCode, S_CNTR_CODE = locCntrCg.CntrCode, S_CNTR_TYPE = locCntrCg.CntrType ?? "" }; loc.N_CURRENT_NUM = 1; if (db.Insertable<TN_Loc_Container>(newLocCntrRel).ExecuteCommand() <= 0 && db.Updateable<TN_Location>(loc).UpdateColumns(c => c.N_CURRENT_NUM).ExecuteCommand() <= 0) { tran.RollbackTran(); LogHelper.Info($"插入位置托盘关系{locCntrCg.LocCode}-{locCntrCg.CntrCode}失败"); return "插入失败"; } } if (string.IsNullOrEmpty(locCntrCg.ItemCode)) { LogHelper.Info("物料号为空,不再读取后面的数据"); return ""; } var cgDetail = db.Queryable<TN_CG_Detail>().First(a => a.S_CNTR_CODE == locCntrCg.CntrCode && a.S_ITEM_CODE == locCntrCg.ItemCode); if (cgDetail == null) { var locList = new List<TN_CG_Detail>(); locList.Add(new TN_CG_Detail { S_CNTR_CODE = locCntrCg.CntrCode, S_ITEM_CODE = locCntrCg.ItemCode, S_BATCH_NO = locCntrCg.BatchNo ?? "" }); if (db.Insertable<TN_CG_Detail>(locList).ExecuteCommand() <= 0) { tran.RollbackTran(); LogHelper.Info($"插入托盘物料关系{locCntrCg.CntrCode}-{locCntrCg}失败"); return "插入失败"; } } tran.CommitTran(); } return "插入数据成功"; } catch (Exception ex) { return $"Error reading CSV file: {ex.Message}"; } } } /// <summary> /// 模拟 AGV 传递信号,用于更改任务状态 /// </summary> public class UpdateTaskState { /// <summary> /// 任务ID /// </summary> public string TaskID { set; get; } /// <summary> /// AGV 小车号 /// </summary> public string ForkliftNo { set; get; } /// <summary> /// AGV 下一个状态 /// </summary> public int NextState { set; get; } } public class CoverInfo { public bool IsCover { set; get; } = false; } /// <summary> /// /// </summary> public class ReturnResults { public List<ReturnResult> ResultList { set; get; } } public class LocCntrCg { public string Note { get; set; } // 仅用于备注 public string LocCode { get; set; } public string LocArea { get; set; } public string CntrCode { get; set; } public string CntrType { get; set; } public string ItemCode { get; set; } public string BatchNo { get; set; } } } api/ErpController.cs
File was renamed from Controllers/ErpController.cs @@ -1,11 +1,10 @@ using System; using HH.WCS.Mobox3.DSZSH.AppStart; using Newtonsoft.Json; using System.Collections.Generic; using System.Web.Http; namespace HH.WCS.Mobox3.DSZSH.Controllers { namespace HH.WCS.Mobox3.DSZSH.api { /// <summary> /// ERP 调用的接口 /// </summary> api/MesController.cs
File was renamed from Controllers/MesController.cs @@ -5,9 +5,7 @@ using System.Threading.Tasks; using System.Web.Http; using HH.WCS.Mobox3.DSZSH.Services; namespace HH.WCS.Mobox3.DSZSH.Controllers { namespace HH.WCS.Mobox3.DSZSH.api { /// <summary> /// MES 调用的接口 /// </summary> api/MoboxController.cs
File was renamed from Controllers/MoboxController.cs @@ -1,23 +1,18 @@ using System.Web.Http; using HH.WCS.Mobox3.DSZSH.Consts; using HH.WCS.Mobox3.DSZSH.Helpers; using HH.WCS.Mobox3.DSZSH.Models; using HH.WCS.Mobox3.DSZSH.Services; using HH.WCS.Mobox3.DSZSH.models; using Newtonsoft.Json; using static HH.WCS.Mobox3.DSZSH.Dtos.Request.MoboxRequest; using static HH.WCS.Mobox3.DSZSH.Dtos.Response.MoboxResponse; using static HH.WCS.Mobox3.DSZSH.api.ApiModel; using static HH.WCS.Mobox3.DSZSH.api.OtherModel; namespace HH.WCS.Mobox3.DSZSH.Controllers { namespace HH.WCS.Mobox3.DSZSH.api { /// <summary> /// Mobox3 调用,脚本中调用(包括 PDA 的接口) /// </summary> [RoutePrefix("api")] public class MoboxController : ApiController { #region PDA 接口 /// <summary> /// 好运箱-满托下线入库(PDA) /// </summary> @@ -27,7 +22,7 @@ [Route("goodpack-offline")] public SimpleResult GoodpackOffline(GoodpackOfflineInfo model) { LogHelper.InfoApi("好运箱-满托下线入库(PDA)", model); return MoboxService.GoodpackOffline(model); return ApiHelper.GoodpackOffline(model); } ///// <summary> @@ -40,11 +35,11 @@ // if (model.CntrType == "托盘") { // //LogHelper.Info($"触发API:空托绑定 " + JsonConvert.SerializeObject(model), "API"); // return MoboxService.EmptyBindPallet(model); // return ApiHelper.EmptyBindPallet(model); // } // else if (model.CntrType == "好运箱") { // //LogHelper.Info($"触发API:空箱绑定 " + JsonConvert.SerializeObject(model), "API"); // return MoboxService.EmptyBindGoodpack(model); // return ApiHelper.EmptyBindGoodpack(model); // } // else { // return BuildSimpleResult(-1, $"不合法的容器类型:'{model.CntrType}'"); @@ -62,13 +57,13 @@ LogHelper.InfoApi("空托/空箱入库", model); if (model.CntrType == "托盘") { return MoboxService.EmptyInboundPallet(model); return ApiHelper.EmptyInboundPallet(model); } else if (model.CntrType == "好运箱") { return MoboxService.EmptyInboundGoodpack(model); return ApiHelper.EmptyInboundGoodpack(model); } else { return BuildSimpleResult(-1, $"容器类型 '{model.CntrType}' 不合法:应为 '托盘' 或 '好运箱'"); return NewSimpleResult(-1, $"容器类型 '{model.CntrType}' 不合法:应为 '托盘' 或 '好运箱'"); } } @@ -87,14 +82,14 @@ // if (locCntrRel.S_CNTR_TYPE == "托盘") { // return MoboxService.EmptyOnlinePallet(new EmptyOnlinePalletInfo { // return ApiHelper.EmptyOnlinePallet(new EmptyOnlinePalletInfo { // CntId = locCntrRel.S_CNTR_CODE, // EndLoc = model.EndLoc // }); // } // else if (locCntrRel.S_CNTR_TYPE == "好运箱") { // return MoboxService.EmptyOnlineGoodpack(new EmptyOnlineGoodpackInfo { // return ApiHelper.EmptyOnlineGoodpack(new EmptyOnlineGoodpackInfo { // CntId = locCntrRel.S_CNTR_CODE, // EndLoc = model.EndLoc // }); @@ -112,7 +107,7 @@ [HttpPost] [Route("empty-online-pallet")] public SimpleResult EmptyOnlinePallet(EmptyOnlinePalletInfo model) { return MoboxService.EmptyOnlinePallet(model); return ApiHelper.EmptyOnlinePallet(model); } /// <summary> @@ -123,7 +118,7 @@ [HttpPost] [Route("empty-online-goodpack")] public SimpleResult EmptyOnlineGoodpack(EmptyOnlineGoodpackInfo model) { return MoboxService.EmptyOnlineGoodpack(model); return ApiHelper.EmptyOnlineGoodpack(model); } ///// <summary> @@ -137,10 +132,10 @@ // LogHelper.InfoApi("合格回库/不合格移库", model); // if (model.Qualified) { // return MoboxService.QualifiedBack(model); // return ApiHelper.QualifiedBack(model); // } // else { // return MoboxService.UnqualifiedShift(model); // return ApiHelper.UnqualifiedShift(model); // } //} @@ -151,7 +146,7 @@ [HttpPost] [Route("qualified-back")] public SimpleResult QualifiedBack(QualifiedBackInfo model) { return MoboxService.QualifiedBack(model); return ApiHelper.QualifiedBack(model); } /// <summary> @@ -161,7 +156,7 @@ [HttpPost] [Route("unqualified-shift")] public SimpleResult UnqualifiedShift(UnqualifiedShiftInfo model) { return MoboxService.UnqualifiedShift(model); return ApiHelper.UnqualifiedShift(model); } /// <summary> @@ -172,7 +167,7 @@ [HttpPost] [Route("rest-back")] public SimpleResult RestBack(RestBackInfo model) { return MoboxService.RestBack(model); return ApiHelper.RestBack(model); } /// <summary> @@ -186,15 +181,13 @@ LogHelper.InfoApi("成品胶出库(PDA)", model); if (model.ForcedOut) { return MoboxService.FinishedOutboundForce(model); return ApiHelper.FinishedOutboundForce(model); } else { return MoboxService.FinishedOutbound(model); return ApiHelper.FinishedOutbound(model); } } #endregion #region Mobox 接口 /// <summary> /// 抽检-创建抽检单(WMS) /// </summary> @@ -203,7 +196,7 @@ [HttpPost] [Route("create-check-order")] public SimpleResult CreateCheckOrder(CreateCheckOrderInfo model) { return MoboxService.CreateCheckOrder(model); return ApiHelper.CreateCheckOrder(model); } /// <summary> @@ -214,8 +207,7 @@ [HttpPost] [Route("shift-storage")] public SimpleResult CreateShiftOrder(CreateShiftOrderInfo model) { return MoboxService.CreateShiftOrder(model); return ApiHelper.CreateShiftOrder(model); } #endregion } } api/WMSController.cs
File was renamed from Controllers/WmsController.cs @@ -1,14 +1,10 @@ using HH.WCS.Mobox3.DSZSH.AppStart; using HH.WCS.Mobox3.DSZSH.Services; using Newtonsoft.Json; using Newtonsoft.Json; using System.Collections.Generic; using System.Web.Http; using static HH.WCS.Mobox3.DSZSH.Dtos.Request.WmsRequest; using static HH.WCS.Mobox3.DSZSH.Dtos.Response.WmsResponse; using static HH.WCS.Mobox3.DSZSH.api.OtherModel; namespace HH.WCS.Mobox3.DSZSH.Controllers namespace HH.WCS.Mobox3.DSZSH.api { /// <summary> /// 第三方调用的接口 @@ -23,7 +19,7 @@ [HttpPost] //[Route("WMS/CgInfoSync")] public WmsResult CgInfoSync(CgInfoSyncInfo model) { return WmsService.CgInfoSync(model); return ApiHelper.CgInfoSync(model); } } } core/Monitor.cs
New file @@ -0,0 +1,395 @@ using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using HH.WCS.Mobox3.DSZSH.models; using HH.WCS.Mobox3.DSZSH.util; using HH.WCS.Mobox3.DSZSH.wms; using Newtonsoft.Json; namespace HH.WCS.Mobox3.DSZSH.core { public class Monitor { public static void CheckOutboundOrder() { var taskName = TaskName.成品胶出库; var db = new SqlHelper<object>().GetInstance(); var info = ""; try { var orderList = db.Queryable<TN_Outbound_Order>() .Where(c => c.N_B_STATE == 1) .OrderBy(c => c.T_CREATE, SqlSugar.OrderByType.Asc) .ToList(); if (orderList.Count == 0) { LogHelper.Info("轮询--出库--暂无待执行的Order"); return; } var detailList = new List<TN_Outbound_Detail>(); foreach (var order in orderList) { var doingCount = db.Queryable<TN_Outbound_Detail>() .Count(d => d.S_OO_NO == order.S_NO && d.N_B_STATE >= 2); // 执行中 var allCount = db.Queryable<TN_Outbound_Detail>() .Count(d => d.S_OO_NO == order.S_NO); LogHelper.Info($"轮询--出库--统计出库单'{order.S_NO}'任务已下发:{doingCount}/{allCount}"); if (doingCount == allCount) { order.N_B_STATE = 2; // 所有任务都已执行 db.Updateable<TN_Outbound_Order>(order).UpdateColumns(it => new { it.N_B_STATE }).ExecuteCommand(); continue; } var lastDetail = db.Queryable<TN_Outbound_Detail>() .Where(d => d.S_OO_NO == order.S_NO && d.N_B_STATE == 2) // TODO 或者改成查task .First(); if (lastDetail != null) { LogHelper.Info($"轮询--出库--出库单'{order.S_NO}'上一个任务仍在进行中:" + JsonConvert.SerializeObject(lastDetail)); continue; } var outboundDetail = db.Queryable<TN_Outbound_Detail>() .Where(a => a.S_OO_NO == order.S_NO && a.N_B_STATE == 1) // 已下发 .First(); if (outboundDetail != null) { LogHelper.Info($"轮询--出库--"); continue; } detailList.Add(outboundDetail); } if (detailList.Count == 0) { return; } var startLocList = new List<TN_Location>(); var endLocList = new List<TN_Location>(); var taskList = new List<TN_Task>(); foreach (var detail in detailList) { var startLoc = db.Queryable<TN_Location>() .LeftJoin<TN_Loc_Container>((l, c) => l.S_CODE == c.S_LOC_CODE) .Where((l, c) => c.S_CNTR_CODE == detail.S_CNTR_CODE) .First(); if (startLoc == null) { LogHelper.Info($"轮询--出库:没有找到合适的起点货位!"); continue; } var endLoc = db.Queryable<TN_Location>() .Where(a => a.S_AREA_CODE == detail.S_END_AREA) .Where(a => a.N_LOCK_STATE == 0 && a.S_LOCK_STATE == "无" && a.C_ENABLE == "Y") .Where(a => a.N_CURRENT_NUM == 0).First(); if (endLoc == null) { LogHelper.Info($"轮询--出库:没有找到合适的终点货位!S_NO为 '{detail.S_OO_NO}',要求Area为 '{detail.S_END_AREA}'"); continue; } detail.N_B_STATE = 2; var cntId = detail.S_CNTR_CODE; var task = WCSHelper.BuildTask(startLoc, endLoc, cntId, taskName); LocationHelper.LockLoc(ref startLoc, 1); // 起点出库锁 LocationHelper.LockLoc(ref endLoc, 2); // 终点入库锁 using (var tran = db.Ado.UseTran()) { if (db.Updateable<TN_Outbound_Detail>(detail).UpdateColumns(it => it.N_B_STATE).ExecuteCommand() <= 0) { tran.RollbackTran(); LogHelper.Info($"轮询--出库--修改明细表状态为完成失败!"); } if (db.Updateable<TN_Location>(startLoc).UpdateColumns(it => new { it.N_LOCK_STATE, it.S_LOCK_STATE, it.S_LOCK_OP, it.T_MODIFY }).ExecuteCommand() <= 0) { tran.RollbackTran(); info = $"生成 {taskName} 失败,容器号 {cntId} ,起点 {startLoc.S_CODE} ,终点货位 {endLoc.S_CODE}"; LogHelper.Info(info); continue; } if (db.Updateable<TN_Location>(endLoc).UpdateColumns(it => new { it.N_LOCK_STATE, it.S_LOCK_STATE, it.S_LOCK_OP, it.T_MODIFY }).ExecuteCommand() <= 0) { tran.RollbackTran(); info = $"生成 {taskName} 失败,容器号 {cntId} ,起点 {startLoc.S_CODE} ,终点货位 {endLoc.S_CODE}"; LogHelper.Info(info); continue; } if (db.Insertable<TN_Task>(task).ExecuteCommand() <= 0) { tran.RollbackTran(); info = $"生成 {taskName} 失败,容器号 {cntId} ,起点 {startLoc.S_CODE} ,终点货位 {endLoc.S_CODE}"; LogHelper.Info(info); continue; } tran.CommitTran(); info = $"生成 {taskName} 成功,容器号 {cntId} ,起点 {startLoc.S_CODE} ,终点货位 {endLoc.S_CODE}"; LogHelper.Info(info); continue; } } } catch (Exception ex) { LogHelper.InfoEx(ex); } } public static void CheckCheckOrder() { var taskName = TaskName.抽检_出库; var db = new SqlHelper<object>().GetInstance(); var info = ""; try { var orderList = db.Queryable<TN_Check_Order>() .Where(c => c.N_B_STATE == 1) .OrderBy(c => c.T_CREATE, SqlSugar.OrderByType.Asc) .ToList(); if (orderList.Count == 0) { LogHelper.Info($"轮询--{taskName}--暂无待执行的{taskName}单"); return; } var detailList = new List<TN_Check_Detail>(); foreach (var order in orderList) { var doingCount = db.Queryable<TN_Check_Detail>() .Count(d => d.S_NO == order.S_NO && d.N_B_STATE >= 2); // 执行中 var allCount = db.Queryable<TN_Check_Detail>() .Count(d => d.S_NO == order.S_NO); LogHelper.Info($"轮询--{taskName}--统计{taskName}单'{order.S_NO}'任务已下发:{doingCount}/{allCount}"); if (doingCount == allCount) { order.N_B_STATE = 2; // 所有任务都已执行 db.Updateable<TN_Check_Order>(order).UpdateColumns(it => new { it.N_B_STATE }).ExecuteCommand(); continue; } var checkDetailList = db.Queryable<TN_Check_Detail>() .Where(a => a.S_NO == order.S_NO && a.N_B_STATE == 1) // 已下发 .ToList(); if (checkDetailList.Count == 0) { LogHelper.Info($"轮询--"); continue; } foreach (var checkDetail in checkDetailList) { detailList.Add(checkDetail); } } foreach (var detail in detailList) { var startLoc = db.Queryable<TN_Location>() .LeftJoin<TN_Loc_Container>((l, c) => l.S_CODE == c.S_LOC_CODE) .Where((l, c) => c.S_CNTR_CODE == detail.S_CNTR_CODE) .First(); if (startLoc == null) { LogHelper.Info($"轮询--{taskName}:没有找到合适的起点货位!"); continue; } var endLoc = db.Queryable<TN_Location>() .Where(l => l.S_AREA_CODE == detail.S_END_AREA) .Where(a => a.N_LOCK_STATE == 0 && a.S_LOCK_STATE == "无" && a.C_ENABLE == "Y") // 筛选:未上锁 .Where(a => a.N_CURRENT_NUM == 0).First(); if (endLoc == null) { LogHelper.Info($"轮询--{taskName}:没有找到合适的终点货位!"); continue; } detail.N_B_STATE = 2; var cntId = detail.S_CNTR_CODE; var task = WCSHelper.BuildTask(startLoc, endLoc, cntId, taskName); LocationHelper.LockLoc(ref startLoc, 1); // 起点出库锁 LocationHelper.LockLoc(ref endLoc, 2); // 终点入库锁 using (var tran = db.Ado.UseTran()) { if (db.Updateable<TN_Check_Detail>(detail).UpdateColumns(it => it.N_B_STATE).ExecuteCommand() <= 0) { tran.RollbackTran(); LogHelper.Info($"轮询--{taskName}:修改{taskName}单明细表状态为完成--失败!"); continue; } if (db.Updateable<TN_Location>(startLoc).UpdateColumns(it => new { it.N_LOCK_STATE, it.S_LOCK_STATE, it.S_LOCK_OP, it.T_MODIFY }).ExecuteCommand() <= 0) { tran.RollbackTran(); info = $"生成 {taskName} 失败,容器号 {cntId} ,起点 {startLoc.S_CODE} ,终点货位 {endLoc.S_CODE}"; LogHelper.Info(info); continue; } if (db.Updateable<TN_Location>(endLoc).UpdateColumns(it => new { it.N_LOCK_STATE, it.S_LOCK_STATE, it.S_LOCK_OP, it.T_MODIFY }).ExecuteCommand() <= 0) { tran.RollbackTran(); info = $"生成 {taskName} 失败,容器号 {cntId} ,起点 {startLoc.S_CODE} ,终点货位 {endLoc.S_CODE}"; LogHelper.Info(info); continue; } if (db.Insertable<TN_Task>(task).ExecuteCommand() <= 0) { tran.RollbackTran(); info = $"生成 {taskName} 失败,容器号 {cntId} ,起点 {startLoc.S_CODE} ,终点货位 {endLoc.S_CODE}"; LogHelper.Info(info); continue; } tran.CommitTran(); info = $"生成 {taskName} 成功,容器号 {cntId} ,起点 {startLoc.S_CODE} ,终点货位 {endLoc.S_CODE}"; LogHelper.Info(info); continue; } } } catch (Exception ex) { LogHelper.InfoEx(ex); } } public static void CheckShiftOrder() { var taskName = TaskName.移库; var db = new SqlHelper<object>().GetInstance(); var info = ""; try { var orderList = db.Queryable<TN_Shift_Order>() .Where(c => c.N_B_STATE == 1) .OrderBy(c => c.T_CREATE, SqlSugar.OrderByType.Asc) .ToList(); if (orderList.Count == 0) { LogHelper.Info($"轮询--{taskName}--暂无待执行的{taskName}单"); return; } var detailList = new List<TN_Shift_Detail>(); foreach (var order in orderList) { var doingCount = db.Queryable<TN_Shift_Detail>() .Count(d => d.S_NO == order.S_NO && d.N_B_STATE >= 2); // 执行中 var allCount = db.Queryable<TN_Shift_Detail>() .Count(d => d.S_NO == order.S_NO); LogHelper.Info($"轮询--{taskName}--统计{taskName}单'{order.S_NO}'任务已下发:{doingCount}/{allCount}"); if (doingCount == allCount) { order.N_B_STATE = 2; // 所有任务都已执行 db.Updateable<TN_Shift_Order>(order).UpdateColumns(it => new { it.N_B_STATE }).ExecuteCommand(); continue; } var checkDetailList = db.Queryable<TN_Shift_Detail>() .Where(a => a.S_NO == order.S_NO && a.N_B_STATE == 1) // 已下发 .ToList(); if (checkDetailList.Count == 0) { LogHelper.Info($"轮询--"); continue; } foreach (var checkDetail in checkDetailList) { detailList.Add(checkDetail); } } foreach (var detail in detailList) { var startLoc = db.Queryable<TN_Location>() .LeftJoin<TN_Loc_Container>((l, c) => l.S_CODE == c.S_LOC_CODE) .Where((l, c) => c.S_CNTR_CODE == detail.S_CNTR_CODE) .First(); if (startLoc == null) { LogHelper.Info($"轮询--{taskName}:没有找到合适的起点货位!"); continue; } var endLoc = db.Queryable<TN_Location>() .Where(l => l.S_AREA_CODE == detail.S_END_AREA) .Where(a => a.N_LOCK_STATE == 0 && a.S_LOCK_STATE == "无" && a.C_ENABLE == "Y") // 筛选:未上锁 .Where(a => a.N_CURRENT_NUM == 0).First(); if (endLoc == null) { LogHelper.Info($"轮询--{taskName}:没有找到合适的终点货位!"); continue; } detail.N_B_STATE = 2; var cntId = detail.S_CNTR_CODE; var task = WCSHelper.BuildTask(startLoc, endLoc, cntId, taskName); LocationHelper.LockLoc(ref startLoc, 1); // 起点出库锁 LocationHelper.LockLoc(ref endLoc, 2); // 终点入库锁 using (var tran = db.Ado.UseTran()) { if (db.Updateable<TN_Shift_Detail>(detail).UpdateColumns(it => it.N_B_STATE).ExecuteCommand() <= 0) { tran.RollbackTran(); LogHelper.Info($"轮询--{taskName}:修改{taskName}单明细表状态为完成--失败!"); continue; } if (db.Updateable<TN_Location>(startLoc).UpdateColumns(it => new { it.N_LOCK_STATE, it.S_LOCK_STATE, it.S_LOCK_OP, it.T_MODIFY }).ExecuteCommand() <= 0) { tran.RollbackTran(); info = $"生成 {taskName} 失败,容器号 {cntId} ,起点 {startLoc.S_CODE} ,终点货位 {endLoc.S_CODE}"; LogHelper.Info(info); continue; } if (db.Updateable<TN_Location>(endLoc).UpdateColumns(it => new { it.N_LOCK_STATE, it.S_LOCK_STATE, it.S_LOCK_OP, it.T_MODIFY }).ExecuteCommand() <= 0) { tran.RollbackTran(); info = $"生成 {taskName} 失败,容器号 {cntId} ,起点 {startLoc.S_CODE} ,终点货位 {endLoc.S_CODE}"; LogHelper.Info(info); continue; } if (db.Insertable<TN_Task>(task).ExecuteCommand() <= 0) { tran.RollbackTran(); info = $"生成 {taskName} 失败,容器号 {cntId} ,起点 {startLoc.S_CODE} ,终点货位 {endLoc.S_CODE}"; LogHelper.Info(info); continue; } tran.CommitTran(); info = $"生成 {taskName} 成功,容器号 {cntId} ,起点 {startLoc.S_CODE} ,终点货位 {endLoc.S_CODE}"; LogHelper.Info(info); continue; } } } catch (Exception ex) { LogHelper.InfoEx(ex); } } } } core/WCSCore.cs
New file @@ -0,0 +1,284 @@ using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using HH.WCS.Mobox3.DSZSH.device; using HH.WCS.Mobox3.DSZSH.models; using HH.WCS.Mobox3.DSZSH.process; using HH.WCS.Mobox3.DSZSH.util; using HH.WCS.Mobox3.DSZSH.wms; using Newtonsoft.Json; using static HH.WCS.Mobox3.DSZSH.api.ApiModel; namespace HH.WCS.Mobox3.DSZSH.core { public class WCSCore { public static ReturnResult OperateAgvTaskStatus(AgvTaskState model) { var result = new ReturnResult(); try { switch (model.state) { case 1023: break; case 1025: break; case 1012: break; case 1004: break; case 1103: break; default: // AGV 执行任务的逻辑处理 if (!AgvTaskProcessOk(model)) { // 执行不OK,说明没有找到任务 result.ResultCode = 1; result.ResultMsg = $"根据Model.No未找到对应的任务,{model.task_no}"; LogHelper.Info(result.ResultMsg, "API"); return result; } break; } result.ResultCode = 0; result.ResultMsg = "success"; LogHelper.Info(result.ResultMsg, "API"); return result; } catch (Exception ex) { result.ResultCode = -1; result.ResultMsg = $"发生了异常:+{ex.Message}"; LogHelper.Info(result.ResultMsg, "Error"); return result; } } /// <summary> /// 执行 AGV 任务,查询不到任务返回 <see langword="false"/> /// </summary> /// <param name="model"></param> /// <returns></returns> private static bool AgvTaskProcessOk(AgvTaskState model) { var TN_Task = WCSHelper.GetTask(model.task_no); // 根据当前model编号查询任务 if (TN_Task == null) { return false; } if (model.state > 7) { //安全请求等 TaskProcess.OperateReq(model.task_no, model.state, model.forklift_no, model.ext_data); return true; } // AGV 任务 134562(7) 状态处理 switch (model.state) { case 1: // 执行 WCSHelper.Begin(TN_Task, model.forklift_no); // 已推送的任务的状态改成执行 break; case 3: // 开始取货 WCSHelper.UpdateStatus(TN_Task, "开始取货"); // 任务状态改成开始取货 break; case 4: // 取货完成 WCSHelper.UpdateStatus(TN_Task, "取货完成"); // 任务状态改成取货完成 TaskProcess.OperateStatus(TN_Task, 4); // 起点容器货位解绑,解锁起点 if (TN_Task.S_TYPE == TaskName.成品胶出库) { var nextOutboundTask = Task.Run(() => { UpdateOutboundTaskState(3); }); } break; case 5: // 开始卸货 WCSHelper.UpdateStatus(TN_Task, "开始卸货"); // 任务状态改成开始卸货 break; case 6: // 卸货完成 WCSHelper.UpdateStatus(TN_Task, "卸货完成"); // 任务状态改成卸货完成 TaskProcess.OperateStatus(TN_Task, 6); // 终点容器货位绑定,解锁终点 break; case 2: // 完成 WCSHelper.End(TN_Task); // 任务状态改成结束 if (TN_Task.S_TYPE == TaskName.抽检_出库) { var checkCompleteTask = Task.Run(() => { UpdateCheckTaskState(3); }); } break; case 7: // 异常 TaskProcess.OperateStatus(TN_Task, 7); // 异常处理 WCSHelper.Fail(TN_Task); // 任务状态改成错误 break; } // 将AGV执行状态,加入TN_Task_Action表中 WCSHelper.AddActionRecord(model.task_no, model.state, model.forklift_no, model.ext_data); //调用第三方接口(如果有)TaskProcess.ReportStatus,添加任务动作关系表 return true; } public static ReturnResult SafetyInteraction(SafetyInteractionInfo model) { var gzResult = new ReturnResult(); var db = new SqlHelper<object>().GetInstance(); ModbusHelper.Relink(); try { var prodLineInfo = Settings.ProductionLines[0]; var prodLineDevice = new ProductionLineDevice(prodLineInfo.PlcIp, prodLineInfo.PlcPort); if (!prodLineDevice.LoadDeviceStateOk()) { LogHelper.Info("加载设备信息失败"); } var tn_task = db.Queryable<TN_Task>().First(a => a.S_CODE == model.task_no); if (tn_task == null) { LogHelper.Info($"任务号 '{model.task_no}' 不存在"); } // 待修改:补充不同分支AGV判断 if (prodLineDevice.SystemState == 1) { if (prodLineDevice.FullOffline == 1 && tn_task.S_TYPE == TaskName.托盘_满托下线入库) { prodLineDevice.AgvPicking = 1; } if (prodLineDevice.AllowAgvPlacePallet == 1 && tn_task.S_TYPE == TaskName.托盘_空托上线) { prodLineDevice.AgvPlacingPallet = 1; } } LogHelper.Info(JsonConvert.SerializeObject(prodLineDevice, Formatting.Indented)); return gzResult; } catch (Exception ex) { LogHelper.Info($"发生了异常:{ex.Message}"); return gzResult; } } public static void UpdateOutboundTaskState(int spotStateCode) { var db = new SqlHelper<object>().GetInstance(); var detail = db.Queryable<TN_Outbound_Detail>() .First(d => d.N_B_STATE == 2); if (detail == null) { LogHelper.Info("出库--AGV取货--查询Detail:当前没有 执行中 的Detail表!"); return; } using (var tran = db.Ado.UseTran()) { detail.N_B_STATE = spotStateCode; if (db.Updateable<TN_Outbound_Detail>(detail).UpdateColumns(it => it.N_B_STATE).ExecuteCommand() <= 0) { tran.RollbackTran(); LogHelper.Info("出库--AGV取货:修改Detail状态 N_B_STATE 为 3任务执行完成 失败!"); return; } var finishedCount = db.Queryable<TN_Outbound_Detail>().Count(d => d.S_OO_NO == detail.S_OO_NO && d.N_B_STATE == 3); var allCount = db.Queryable<TN_Outbound_Detail>().Count(d => d.S_OO_NO == detail.S_OO_NO); LogHelper.Info($"出库--AGV取货--统计任务已完成:{finishedCount} / {allCount}"); if (finishedCount == allCount) { // 当前出库单下的所有明细单,任务都已经完成 if (db.Updateable<TN_Outbound_Order>().SetColumns(it => it.N_B_STATE == 3) .Where(it => it.S_NO == detail.S_OO_NO) .ExecuteCommand() <= 0) { tran.RollbackTran(); LogHelper.Info("出库--AGV取货--所有任务完成时:修改Order状态 N_B_STATE 为 3任务执行完成 失败!"); return; } } tran.CommitTran(); } } public static void UpdateCheckTaskState(int spotStateCode) { var db = new SqlHelper<object>().GetInstance(); var detail = db.Queryable<TN_Check_Detail>() .First(d => d.N_B_STATE == 2); if (detail == null) { LogHelper.Info("抽检--AGV任务完成--查询Detail:当前没有 执行中 的Detail表!"); return; } using (var tran = db.Ado.UseTran()) { detail.N_B_STATE = spotStateCode; if (db.Updateable<TN_Check_Detail>(detail).UpdateColumns(it => it.N_B_STATE).ExecuteCommand() <= 0) { tran.RollbackTran(); LogHelper.Info("抽检--AGV任务完成:修改Detail状态 N_B_STATE 为 3任务执行完成 失败!"); return; } var finishedCount = db.Queryable<TN_Check_Detail>().Count(d => d.S_NO == detail.S_NO && d.N_B_STATE == 3); var allCount = db.Queryable<TN_Check_Detail>().Count(d => d.S_NO == detail.S_NO); LogHelper.Info($"抽检--AGV任务完成:统计任务已完成:{finishedCount} / {allCount}"); if (finishedCount == allCount) { // 当前order下的detail,任务都已经完成 if (db.Updateable<TN_Check_Order>().SetColumns(it => it.N_B_STATE == 3) .Where(it => it.S_NO == detail.S_NO) .ExecuteCommand() <= 0) { tran.RollbackTran(); LogHelper.Info("抽检--AGV任务完成--所有任务完成时:修改Order状态 N_B_STATE 为 3任务执行完成 失败!"); return; } } tran.CommitTran(); } } public static void UpdateShiftTaskState(int spotStateCode) { var db = new SqlHelper<object>().GetInstance(); var detail = db.Queryable<TN_Shift_Detail>() .First(d => d.N_B_STATE == 2); if (detail == null) { LogHelper.Info("移库--AGV任务完成--查询Detail:当前没有 执行中 的Detail表!"); return; } detail.N_B_STATE = spotStateCode; var finishedCount = db.Queryable<TN_Shift_Detail>().Count(d => d.S_NO == detail.S_NO && d.N_B_STATE == 3); var allCount = db.Queryable<TN_Shift_Detail>().Count(d => d.S_NO == detail.S_NO); LogHelper.Info($"移库--AGV任务完成:统计任务已完成:{finishedCount} / {allCount}"); using (var tran = db.Ado.UseTran()) { if (db.Updateable<TN_Shift_Detail>(detail).UpdateColumns(it => it.N_B_STATE).ExecuteCommand() <= 0) { tran.RollbackTran(); LogHelper.Info("移库--AGV任务完成:修改Detail状态 N_B_STATE 为 3任务执行完成 失败!"); return; } if (finishedCount == allCount) { // 当前order下的detail,任务都已经完成 if (db.Updateable<TN_Shift_Order>().SetColumns(it => it.N_B_STATE == 3) .Where(it => it.S_NO == detail.S_NO) .ExecuteCommand() <= 0) { tran.RollbackTran(); LogHelper.Info("移库--AGV任务完成--所有任务完成时:修改Order状态 N_B_STATE 为 3任务执行完成 失败!"); return; } } tran.CommitTran(); } } } } core/WMSCore.cs
File was renamed from ServiceCore/DebugCore.cs @@ -4,8 +4,8 @@ using System.Text; using System.Threading.Tasks; namespace HH.WCS.Mobox3.DSZSH.ServiceCore { public class DebugCore { namespace HH.WCS.Mobox3.DSZSH.core { public class WMSCore { } } device/ModbusHelper.cs
File was renamed from Devices/ModbusHelper.cs @@ -5,7 +5,7 @@ using EasyModbus; namespace HH.WCS.Mobox3.DSZSH.Helpers { namespace HH.WCS.Mobox3.DSZSH.device { /// <summary> /// modbus tcp 用第三方的包 /// </summary> device/OpcUaHelper.cs
device/PlcHelper.cs
File was renamed from Devices/PlcHelper.cs @@ -1,9 +1,10 @@ using HH.WCS.Mobox3.DSZSH.Helpers; using System; using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using HH.WCS.Mobox3.DSZSH.process; namespace HH.WCS.Mobox3.DSZSH.device { @@ -15,7 +16,6 @@ } internal static bool SendHex(string ip, string msg) { return TcpServer.TcpServerSend(ip, Hex2Bytes(msg)); } internal static void SendAscii(string ip, string msg) { TcpServer.TcpServerSend(ip, Encoding.ASCII.GetBytes(msg)); device/ProductionLineDevice.cs
File was renamed from Devices/ProductionLineDevice.cs @@ -1,10 +1,8 @@ using System; using HH.WCS.Mobox3.DSZSH.Helpers; using Newtonsoft.Json; namespace HH.WCS.Mobox3.DSZSH.Devices { namespace HH.WCS.Mobox3.DSZSH.device { /// <summary> /// 输送线PLC设备 /// </summary> device/S7Helper.cs
File was renamed from Devices/S7Helper.cs @@ -1,4 +1,4 @@ using HH.WCS.Mobox3.DSZSH.Controllers; using HH.WCS.Mobox3.DSZSH.api; using Newtonsoft.Json.Linq; using S7.Net; using S7.Net.Types; device/TcpClient.cs
device/TcpServer.cs
File was renamed from Devices/TcpServer.cs @@ -1,5 +1,4 @@ using HH.WCS.Mobox3.DSZSH.Dispatch; using HH.WCS.Mobox3.DSZSH.AppStart; using HH.WCS.Mobox3.DSZSH.dispatch; using Newtonsoft.Json; using System; using System.Collections.Generic; process/DeviceProcess.cs
File was renamed from Helpers/DeviceProcess.cs @@ -1,14 +1,12 @@ using HH.WCS.Mobox3.DSZSH.device; using HH.WCS.Mobox3.DSZSH.Dispatch; using HH.WCS.Mobox3.DSZSH.AppStart; using HH.WCS.Mobox3.DSZSH.Helper; using HH.WCS.Mobox3.DSZSH.dispatch; using System; using System.Collections.Generic; using System.Linq; using System.Threading; namespace HH.WCS.Mobox3.DSZSH.Helpers namespace HH.WCS.Mobox3.DSZSH.process { /// <summary> /// 设备信号处理,主要是tcp信号,我们做server被动接收信号来处理,根据项目定制的 process/TaskProcess.cs
New file @@ -0,0 +1,196 @@ using Newtonsoft.Json; using SqlSugar; using System.Collections.Generic; using System.Linq; using System; using HH.WCS.Mobox3.DSZSH.dispatch; using HH.WCS.Mobox3.DSZSH.models; using HH.WCS.Mobox3.DSZSH.wms; using HH.WCS.Mobox3.DSZSH; namespace HH.WCS.Mobox3.DSZSH.process { internal class TaskProcess { #region 任务相关 //--------------------------------------------------任务相关-------------------------------------------------- /// <summary> /// 取货卸货完成,缓存位状态更新 /// </summary> /// <param name="mst"></param> /// <param name="load"></param> internal static void CacheBitUpdate(TN_Task mst, bool load) { //var trayCarryCount = mst.N_CNTR_COUNT > 0 ? mst.N_CNTR_COUNT : 1; if (load) { Console.WriteLine($"任务{mst.S_CODE} 货位{mst.S_START_LOC}取货完成,起点解绑容器{mst.S_CNTR_CODE}"); LogHelper.Info($"任务{mst.S_CODE} 货位{mst.S_START_LOC}取货完成,起点解绑容器{mst.S_CNTR_CODE}"); LocationHelper.UnBindingLoc(mst.S_START_LOC, mst.S_CNTR_CODE.Split(',').ToList()); } else { Console.WriteLine($"任务{mst.S_CODE} 货位{mst.S_END_LOC}卸货完成,终点绑定容器{mst.S_CNTR_CODE}"); LogHelper.Info($"任务{mst.S_CODE} 货位{mst.S_END_LOC}卸货完成,终点绑定容器{mst.S_CNTR_CODE}"); LocationHelper.BindingLoc(mst.S_END_LOC, mst.S_CNTR_CODE.Split(',').ToList()); } } /// <summary> /// 任务取消,缓存位状态更新 /// </summary> /// <param name="mst"></param> internal static void CacheBitCancelUpdate(TN_Task mst) { //任务取消,取货完成前的,起点的loadingCount和终点unLoadingCount都清除,取货完成的只处理终点 if (WCSHelper.CheckActionRecordExist(mst.S_CODE, 4)) { //根据客户现场要求,如果取货完成任务失败人工拉到终点,我们就当卸货完成处理;如果是人工拉走到其它区域,我们就解锁终点,删除托盘。 //终点绑定 CacheBitUpdate(mst, false); LocationHelper.UnLockLoc(mst.S_END_LOC); } else { //起点终点解锁 LocationHelper.UnLockLoc(mst.S_START_LOC); LocationHelper.UnLockLoc(mst.S_END_LOC); } } /// <summary> /// 任务状态更新处理 /// </summary> /// <param name="mst"></param> /// <param name="state"></param> internal static void OperateStatus(TN_Task mst, int state) { if (state == 4) { CacheBitUpdate(mst, true); } if (state == 6)//卸货完成 { CacheBitUpdate(mst, false); } if (state == 7) { CacheBitCancelUpdate(mst); } } /// <summary> /// 安全请求 /// </summary> /// <param name="no"></param> /// <param name="state"></param> /// <param name="forkliftNo"></param> /// <param name="extData"></param> internal static void OperateReq(string no, int state, string forkliftNo, string extData = "") { if (state == 1101) { //请求取货, } if (state == 1102) { //请求卸货, //根据终点判断,是cb02的入口,判断内存中状态(要状态时间),允许卸货,通知agv改参数 var dic = new Dictionary<string, string>(); //< Req >< Order No = 'TN2302020002' ParamNo = '18' Param1 = '12' /></ Req > dic.Add("No", no); dic.Add("ParamNo", "8"); dic.Add("Param1", "1"); NDC.ChangeOrder(dic); //改完参数车子就会自己卸货 } if (state == 1103) { //大铁框叉走以后通知,我们要通知输送线 } } private static object locLocker = new object(); /// <summary> /// 推送任务 /// </summary> /// <param name="mst"></param> internal static bool SendTask(TN_Task mst) { var result = false; var start = "0"; var end = "0"; var taskType = mst.S_TYPE.Trim(); if (mst.N_B_STATE == 0) { if (mst.N_SCHEDULE_TYPE == 1)//通过NDC,hosttoagv调度设备 { start = LocationHelper.GetAgvSite(mst.S_START_LOC); end = LocationHelper.GetAgvSite(mst.S_END_LOC); //if (mst.S_TYPE == "空托下线堆叠") { // end = LocationHelper.GetAgvSite(mst.S_END_LOC, true); //} LogHelper.Info($"NDC推送任务 {mst.S_CODE};" + "start=" + start + "end= " + end); var startLoc = LocationHelper.GetLoc(mst.S_START_LOC); var endLoc = LocationHelper.GetLoc(mst.S_END_LOC); var dic = new List<param>(); dic.Add(new param() { name = "IKey", value = "IKey" }); dic.Add(new param() { name = "From", value = start.ToString() }); dic.Add(new param() { name = "To", value = end.ToString() }); dic.Add(new param() { name = "FUNC", value = startLoc.N_LAYER.ToString() }); dic.Add(new param() { name = "Ctype", value = "0" }); //if (mst.S_TYPE == "余料下线入库" || mst.S_TYPE == "人工拆盘入库") { // dic.Add(new param() { name = "DATA", value = "1024" }); //} //else { // dic.Add(new param() { name = "DATA", value = "0" }); //} var res = NDCApi.AddOrderNew(1, 1, mst.S_CODE, dic);//添加新命令 if (res != null && (res.err_code == 0 || res.err_code == 50009)) { //推送成功,修改任务优先级 mst.N_B_STATE = 1; mst.S_B_STATE = TN_Task.GetStateStr(1); WCSHelper.UpdateStatus(mst);//更新任务状态 result = true; LogHelper.Info($"NDC推送任务成功 {mst.S_CODE}start= {mst.S_START_LOC} + end = {mst.S_END_LOC}"); } else { LogHelper.Info($"NDC推送任务失败 {mst.S_CODE};Res:" + JsonConvert.SerializeObject(res)); } } else if (mst.N_SCHEDULE_TYPE == 5)//通过杭奥调度设备 { //调第三方接口 var model = new HanAo.TaskInfoModel { requestPk = mst.S_CODE, frmPos = mst.S_START_LOC, toPos = mst.S_END_LOC, trkType = mst.S_OP_NAME == "入库" ? "1" : "2", contNo = mst.S_CNTR_CODE }; if (HanAo.CreateOrder(model)) { mst.N_B_STATE = 1; WCSHelper.UpdateStatus(mst); LogHelper.Info($"杭奥推送任务成功 {mst.S_CODE};" + "start=" + model.frmPos + "end= " + model.toPos); } else { LogHelper.Info($"杭奥推送任务失败 {mst.S_CODE};" + JsonConvert.SerializeObject(model)); } } else if (mst.N_SCHEDULE_TYPE == 3) //通过国自调度设备 { var code = GZRobot.CreateOrder(mst.S_CODE, mst.N_PRIORITY, JsonConvert.SerializeObject(new { src = mst.S_START_LOC, dst = mst.S_END_LOC }), "p2p"); if (code > 0) { //更新任务状态 mst.N_B_STATE = 1; mst.S_EQ_TASK_CODE = code.ToString(); WCSHelper.UpdateStatus(mst); WCSHelper.UpdateEQNo(mst); LogHelper.Info($"国自推送任务成功 {mst.S_CODE};" + "start=" + mst.S_START_LOC + "end= " + mst.S_END_LOC); } else { LogHelper.Info($"国自推送任务失败 {mst.S_CODE};" + JsonConvert.SerializeObject(mst)); } } } return result; } #endregion } } util/HttpHelper.cs
File was renamed from Helpers/HttpHelper.cs @@ -5,7 +5,7 @@ using System.Net; using System.Text; namespace HH.WCS.Mobox3.DSZSH.AppStart { namespace HH.WCS.Mobox3.DSZSH.util { public class HttpHelper { public string WebPost(string url, string postData, string cotentType = "application/json") { util/LogHelper.cs
File was renamed from Helpers/LogHelper.cs @@ -13,7 +13,6 @@ { public static Dictionary<string, ILogger> loggers = new Dictionary<string, ILogger>(); #region 标准方法(Debug/Info/Error) public static void Debug(string message, string name = "") { ILogger logger = null; if (loggers.Keys.Contains(name)) { @@ -70,7 +69,6 @@ logger.Error($"{message}{ex.StackTrace}"); } } #endregion #region 自定义方法 public static void InfoEx(Exception ex) { util/Settings.cs
New file @@ -0,0 +1,158 @@ using System; using System.Collections.Generic; using System.IO; using Newtonsoft.Json; using Newtonsoft.Json.Linq; namespace HH.WCS.Mobox3.DSZSH { public class Settings { public static string WebApiUrl { get; set; } public static string NdcApiUrl { get; set; } public static string SqlServer { get; set; } public static string TcpServerIp { get; set; } public static int TcpServerPort { get; set; } public static List<Config.Area> Areas { get; set; } public static List<Config.Task> Tasks { get; set; } public static List<Config.ProductionLine> ProductionLines { get; set; } /// <summary> /// 库区字典(加载后就不变) /// </summary> public static Dictionary<string, List<string>> AreaMap { get; set; } = new Dictionary<string, List<string>>(); /// <summary> /// 任务字典(加载后就不变) /// </summary> public static Dictionary<string, Config.Task> TaskMap { get; set; } = new Dictionary<string, Config.Task>(); public static void Init() { // 加载配置文件 LoadJson(); // 针对 Areas 进行转换:将 Config 的 List 加载到 Dict 中 LoadAreas(); // 针对 Tasks 进行转换 LoadTasks(); } private static void LoadJson() { LogHelper.Info("加载配置文件信息 开始"); // JSON 文件路径 string filePath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "./config/config.json"); try { // 读取 JSON 文件内容 string jsonContent = File.ReadAllText(filePath); // 反序列化为 Config 对象 var root = JsonConvert.DeserializeObject<Config.Root>(jsonContent); WebApiUrl = root.WebApiUrl; NdcApiUrl = root.NdcApiUrl; SqlServer = root.SqlServer; TcpServerIp = root.TcpServerIp; TcpServerPort = root.TcpServerPort; Areas = root.Areas; Tasks = root.Tasks; ProductionLines = root.ProductionLines; } catch (FileNotFoundException) { LogHelper.Info("JSON 文件未找到"); } catch (JsonException ex) { LogHelper.Info($"JSON 解析错误: {ex.Message}"); } catch (Exception ex) { LogHelper.Info($"发生错误: {ex.Message}"); } LogHelper.Info("加载配置文件信息 完成"); } private static void LoadAreas() { foreach (var area in Areas) { AreaMap.Add(area.Name, area.Codes); } } private static void LoadTasks() { foreach (var task in Tasks) { TaskMap.Add(task.Name, task); } } } public class Config { // Root myDeserializedClass = JsonConvert.DeserializeObject<Root>(myJsonResponse); public class Area { public string Name { get; set; } public List<string> Codes { get; set; } } public class ProductionLine { public string Id { get; set; } public string Name { get; set; } public string PlcIp { get; set; } public int PlcPort { get; set; } public int SlaveId { get; set; } public List<string> OnLoc { get; set; } public List<string> OffLoc { get; set; } } public class Root { public string WebApiUrl { get; set; } public string NdcApiUrl { get; set; } public string SqlServer { get; set; } public string TcpServerIp { get; set; } public int TcpServerPort { get; set; } public List<Area> Areas { get; set; } public List<Task> Tasks { get; set; } public List<ProductionLine> ProductionLines { get; set; } } public class Task { public string Name { get; set; } public List<string> StartAreas { get; set; } public List<string> EndAreas { get; set; } } } public class AreaName { public const string 包装区 = "包装区"; public const string 操作区 = "操作区"; public const string 空托存放区 = "空托存放区"; public const string 货架区 = "货架区"; public const string 空箱存放区 = "空箱存放区"; public const string 满托存放区 = "满托存放区"; public const string 满箱存放区 = "满箱存放区"; public const string 人工_AGV接驳区 = "人工-AGV接驳区"; public const string 空托盘接驳区 = "空托盘接驳区"; public const string 空箱接驳区 = "空箱接驳区"; } public class TaskName { public const string 好运箱_满箱下线入库 = "好运箱-满箱下线入库"; public const string 好运箱_空箱上线 = "好运箱-空箱上线"; public const string 好运箱_空箱入库 = "好运箱-空箱入库"; public const string 好运箱_空箱绑定 = "好运箱-空箱绑定"; public const string 成品胶出库 = "成品胶出库"; public const string 托盘_满托下线入库 = "托盘-满托下线入库"; public const string 托盘_空托上线 = "托盘-空托上线"; public const string 托盘_空托入库 = "托盘-空托入库"; public const string 托盘_空托绑定 = "托盘-空托绑定"; public const string 抽检_不合格移库 = "抽检-不合格移库"; public const string 抽检_出库 = "抽检-出库"; public const string 抽检_合格回库 = "抽检-合格回库"; public const string 移库 = "移库"; public const string 尾箱回库 = "尾箱回库"; } } util/SqlHelper.cs
New file @@ -0,0 +1,63 @@ using System; using System.Linq; using SqlSugar; namespace HH.WCS.Mobox3.DSZSH.util { //https://www.donet5.com/Home/Doc public class SqlHelper<T> where T : class, new() { /// <summary> /// 如果用Oracle数据需要包Oracle.ManagedDataAccess/21.15.0,环境netframework 4.62,太新了4.8有的服务器安装不上去 /// </summary> /// <param name="url"></param> /// <returns></returns> public SqlSugarClient GetInstance(string url = "") { //创建数据库对象 SqlSugarClient db = new SqlSugarClient(new ConnectionConfig() { ConnectionString = string.IsNullOrEmpty(url) ? Settings.SqlServer : url, //ConnectionString = @"Data Source=192.168.1.198\sql2008;Initial Catalog=OIMobox;User ID=sa;Password=sa@2015", DbType = DbType.SqlServer, //ConnectionString = @"Data Source=(DESCRIPTION=(ADDRESS_LIST=(ADDRESS=(PROTOCOL=TCP)(HOST=localhost)(PORT=1521)))(CONNECT_DATA=(SERVER=DEDICATED)(SERVICE_NAME=OIMobox)));User Id=system;Password=Am123123;", //DbType = DbType.Oracle, IsAutoCloseConnection = true, InitKeyType = InitKeyType.Attribute//从特性读取主键自增信息 }); //监控所有超过1秒的Sql db.Aop.OnLogExecuted = (sql, p) => { //执行时间超过1秒 if (db.Ado.SqlExecutionTime.TotalSeconds > 1) { Console.WriteLine(sql + "\r\n" + db.Utilities.SerializeObject(p.ToDictionary(it => it.ParameterName, it => it.Value))); //代码CS文件名 var fileName = db.Ado.SqlStackTrace.FirstFileName; //代码行数 var fileLine = db.Ado.SqlStackTrace.FirstLine; //方法名 var FirstMethodName = db.Ado.SqlStackTrace.FirstMethodName; } //相当于EF的 PrintToMiniProfiler }; //每次设置数值时都去除前导后导空格 db.Aop.DataExecuted = (value, entity) => { entity.EntityColumnInfos.ToList().ForEach(a => { var pvalue = entity.GetValue(a.PropertyName); if (pvalue != null && pvalue.GetType() == typeof(String)) { entity.SetValue(a.PropertyName, pvalue.ToString().Trim()); } }); }; //据转换 (ExecuteCommand才会拦截,查询不行) //db.Aop.DataExecuting = (value, entity) => { // //var val=entity.EntityColumnInfo // Console.WriteLine(entity.EntityName); //}; return db; } } } wms/ContainerHelper.cs
File was renamed from Helpers/ContainerHelper.cs @@ -2,12 +2,12 @@ using System.Collections.Generic; using System.Linq; using HH.WCS.Mobox3.DSZSH.Helpers; using HH.WCS.Mobox3.DSZSH.Models; using HH.WCS.Mobox3.DSZSH.models; using HH.WCS.Mobox3.DSZSH.util; using Newtonsoft.Json; namespace HH.WCS.Mobox3.DSZSH.Helpers { namespace HH.WCS.Mobox3.DSZSH.wms { /// <summary> /// 容器帮助类(包含容器-货品关系的处理) /// </summary> @@ -21,7 +21,7 @@ /// <returns></returns> public static string BindingCG(string cnt, List<string> cGs) { var db = DbHelper.GetDbClient(); var db = new SqlHelper<object>().GetInstance(); var logs = $"容器:{cnt},货品:{JsonConvert.SerializeObject(cGs)}"; try { @@ -86,7 +86,7 @@ /// <returns></returns> public static string UnBindingCG(string cnt, List<string> cGs) { var db = DbHelper.GetDbClient(); var db = new SqlHelper<object>().GetInstance(); var logs = $"容器:{cnt},货品:{JsonConvert.SerializeObject(cGs)}"; try { wms/LocationHelper.cs
File was renamed from Helpers/LocationHelper.cs @@ -2,15 +2,14 @@ using System.Collections.Generic; using System.Linq; using HH.WCS.Mobox3.DSZSH.Models; using HH.WCS.Mobox3.DSZSH.models; using HH.WCS.Mobox3.DSZSH.util; using Newtonsoft.Json; using SqlSugar; using static HH.WCS.Mobox3.DSZSH.Dtos.Response.MoboxResponse; namespace HH.WCS.Mobox3.DSZSH.Helpers { namespace HH.WCS.Mobox3.DSZSH.wms { /// <summary> /// 货位帮助类(包含货位-容器关系的处理) /// </summary> @@ -56,7 +55,7 @@ /// <returns></returns> internal static List<TN_Location> GetAllLocList() { var db = DbHelper.GetDbClient(); var db = new SqlHelper<object>().GetInstance(); return db.Queryable<TN_Location>().ToList(); } @@ -123,8 +122,31 @@ internal static TN_Location GetLoc(string code) { var db = DbHelper.GetDbClient(); var db = new SqlHelper<object>().GetInstance(); return db.Queryable<TN_Location>().Where(a => a.S_CODE.Trim() == code).First(); } /// <summary> /// 入库锁定终点,出库锁定起点 /// 你创建任务锁定货位的时候,把锁的来源就是任务号也写上去(加锁的方法加个参数,可空的参数),解锁的时候把来源置空。 /// </summary> /// <param name="loc"></param> /// <param name="lockState">1:入库锁、2:出库锁、2:其它锁</param> /// <param name="lockSource">锁的来源=任务号</param> /// <returns></returns> public static bool LockLoc(ref TN_Location loc, int lockState, string lockSource = "") { if (loc == null || loc.N_LOCK_STATE != 0) { return false; } if (loc != null && loc.N_LOCK_STATE == 0) { loc.N_LOCK_STATE = lockState; loc.S_LOCK_STATE = TN_Location.GetLockStateStr(lockState); loc.S_LOCK_OP = lockSource; loc.T_MODIFY = System.DateTime.Now; } return true; } /// <summary> @@ -140,7 +162,7 @@ public static bool LockLoc(string loc, int lockState, string lockSource = "") { var res = false; var db = DbHelper.GetDbClient(); var db = new SqlHelper<object>().GetInstance(); var model = db.Queryable<TN_Location>().Where(a => a.S_CODE == loc).First(); LogHelper.Info($"锁货位{loc},状态{lockState},信息" + JsonConvert.SerializeObject(model)); if (model != null && model.N_LOCK_STATE == 0) @@ -165,7 +187,7 @@ { LogHelper.Info("UnLockLoc:" + loc); var res = false; var db = DbHelper.GetDbClient(); var db = new SqlHelper<object>().GetInstance(); var model = db.Queryable<TN_Location>().Where(a => a.S_CODE == loc).First(); if (model != null) { @@ -191,7 +213,7 @@ /// <returns></returns> public static string UnBindingLoc(string loc, List<string> cntrs) { var db = DbHelper.GetDbClient(); var db = new SqlHelper<object>().GetInstance(); var logs = $"货位:{loc},容器:{JsonConvert.SerializeObject(cntrs)}"; try { @@ -264,7 +286,7 @@ /// <returns></returns> public static string BindingLoc(string loc, List<string> cntrs) { var db = DbHelper.GetDbClient(); var db = new SqlHelper<object>().GetInstance(); var logs = $"货位:{loc},容器:{JsonConvert.SerializeObject(cntrs)}"; try { wms/SYSHelper.cs
File was renamed from Helpers/SysHelper.cs @@ -1,19 +1,19 @@ using HH.WCS.Mobox3.DSZSH.Helpers; using HH.WCS.Mobox3.DSZSH.util; using SqlSugar; namespace HH.WCS.Mobox3.DSZSH.Helper { namespace HH.WCS.Mobox3.DSZSH.wms { /// <summary> /// 用于生成序列号,并管理序列号前缀的工具类 /// </summary> internal class SysHelper internal class SYSHelper { //使用静态 locker 对象实现线程同步 private static object locker = new object(); internal static int GetSerialNumber(string snType, string prefix) { int result = 0; lock (locker) { var db = DbHelper.GetDbClient(); var db = new SqlHelper<object>().GetInstance(); var sId = db.Queryable<OI_SYS_MAXID>().Where(a => a.CN_S_TYPE.Trim() == snType && a.CN_S_PRE.Trim() == prefix).First(); if (sId != null) { sId.CN_N_MAX++; wms/WCSHelper.cs
New file @@ -0,0 +1,224 @@ using HH.WCS.Mobox3.DSZSH.models; using HH.WCS.Mobox3.DSZSH.util; using HH.WCS.Mobox3.DSZSH; using Newtonsoft.Json; using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace HH.WCS.Mobox3.DSZSH.wms { internal class WCSHelper { internal static string GenerateTaskNo() { var id = SYSHelper.GetSerialNumber("任务号", "TN"); var date = DateTime.Now.ToString("yyMMdd"); return $"TN{date}{id.ToString().PadLeft(4, '0')}"; } internal static bool UpdateStatus(TN_Task task, string status) { var res = false; var db = new SqlHelper<TN_Task>().GetInstance(); task.S_B_STATE = status; res = db.Updateable(task).UpdateColumns(it => new { it.S_B_STATE }).ExecuteCommand() > 0; return res; } internal static bool UpdateStatus(TN_Task task) { var res = false; var db = new SqlHelper<TN_Task>().GetInstance(); task.S_B_STATE = TN_Task.GetStateStr(task.N_B_STATE); task.T_MODIFY = DateTime.Now; db.Updateable(task).UpdateColumns(it => new { it.N_B_STATE, it.S_B_STATE, it.T_MODIFY }).ExecuteCommand(); return res; } internal static bool UpdateEQNo(TN_Task task) { var res = false; var db = new SqlHelper<TN_Task>().GetInstance(); task.T_MODIFY = DateTime.Now; db.Updateable(task).UpdateColumns(it => new { it.S_EQ_TASK_CODE, it.T_MODIFY }).ExecuteCommand(); return res; } internal static TN_Task GetTask(string no) { var db = new SqlHelper<TN_Task>().GetInstance(); var task = db.Queryable<TN_Task>().Where(a => a.S_CODE == no).First(); return task; } public static TN_Task BuildTask(TN_Location startLoc, TN_Location endLoc, string cntId, string type) { TN_Task TN_Task = new TN_Task() { S_CODE = GenerateTaskNo(), S_START_AREA = startLoc.S_AREA_CODE, S_END_AREA = endLoc.S_AREA_CODE, S_START_LOC = startLoc.S_CODE, S_END_LOC = endLoc.S_CODE, S_TYPE = type, N_PRIORITY = 3, // 初始优先级默认为:3 N_SCHEDULE_TYPE = 3, // 国自 N_B_STATE = 0, S_CNTR_CODE = cntId, }; return TN_Task; } public static TN_Task BuildTask(TN_Loc_Container locCntrRel, TN_Location endLoc, string cntId, string type) { var fromLoc = LocationHelper.GetLocation(locCntrRel.S_LOC_CODE); TN_Task TN_Task = new TN_Task() { S_CODE = GenerateTaskNo(), S_START_AREA = fromLoc.S_AREA_CODE, S_END_AREA = endLoc.S_AREA_CODE, S_START_LOC = fromLoc.S_CODE, S_END_LOC = endLoc.S_CODE, S_TYPE = type, N_PRIORITY = 3, // 初始优先级默认为:3 N_SCHEDULE_TYPE = 3, // 国自 N_B_STATE = 0, S_CNTR_CODE = cntId, }; return TN_Task; } /// <summary> /// 创建搬送任务 /// </summary> /// <param name="no">编号</param> /// <param name="from">起点</param> /// <param name="to">终点</param> /// <param name="taskType">任务类型</param> /// <param name="pri">优先级</param> /// <param name="cntrInfo">容器编码</param> /// <returns></returns> internal static bool CreateTask(string from, string to, string taskType, int pri, string cntrInfo) { var fromLoc = LocationHelper.GetLocation(from); var endLoc = LocationHelper.GetLocation(to); TN_Task TN_Task = new TN_Task() { S_CODE = GenerateTaskNo(), S_START_AREA = fromLoc.S_AREA_CODE, S_END_AREA = endLoc.S_AREA_CODE, S_START_LOC = from, S_END_LOC = to, S_TYPE = taskType, N_PRIORITY = pri, N_SCHEDULE_TYPE = 1, N_B_STATE = 0, S_CNTR_CODE = cntrInfo, }; var log = JsonConvert.SerializeObject(TN_Task); var db = new SqlHelper<TN_Task>().GetInstance(); var res = db.Insertable(TN_Task).ExecuteCommand() > 0; if (res) { LogHelper.Info($"插入任务成功,{log}"); } else { LogHelper.Info($"插入任务失败,{log}"); } return res; } public static bool CreateTask(List<CreateTasks> modes) { if (modes != null && modes.Count > 0) { List<TN_Task> tN_Tasks = new List<TN_Task>(); foreach (var item in modes) { var fromLoc = LocationHelper.GetLocation(item.from); var endLoc = LocationHelper.GetLocation(item.to); tN_Tasks.Add(new TN_Task() { S_CODE = GenerateTaskNo(), S_START_AREA = fromLoc.S_AREA_CODE, S_END_AREA = endLoc.S_AREA_CODE, S_START_LOC = item.from, S_END_LOC = item.to, S_TYPE = item.taskType, N_PRIORITY = item.pri, N_SCHEDULE_TYPE = 1, N_B_STATE = 0, S_CNTR_CODE = item.cntrInfo, }); } var log = JsonConvert.SerializeObject(tN_Tasks); var db = new SqlHelper<object>().GetInstance(); var res = db.Insertable<TN_Task>(tN_Tasks).ExecuteCommand() > 0; if (res) { LogHelper.Info($"插入任务成功,{log}"); } else { LogHelper.Info($"插入任务失败,{log}"); } return res; } return false; } internal static bool CheckActionRecordExist(string no, int code) { var db = new SqlHelper<TN_Task_Action>().GetInstance(); return db.Queryable<TN_Task_Action>().Count(a => a.S_TASK_CODE == no && a.N_ACTION_CODE == code) > 0; } internal static void Begin(TN_Task task, string forklift_no) { var db = new SqlHelper<TN_Task>().GetInstance(); if (task != null) { if (task.N_B_STATE == 1) { task.N_B_STATE = 2; task.S_B_STATE = TN_Task.GetStateStr(task.N_B_STATE); task.T_START_TIME = System.DateTime.Now; task.S_EQ_NO = forklift_no; db.Updateable(task).UpdateColumns(it => new { it.N_B_STATE, it.S_B_STATE, it.T_START_TIME, it.S_EQ_NO }).ExecuteCommand(); } } } internal static void End(TN_Task task) { var db = new SqlHelper<TN_Task>().GetInstance(); if (task != null) { task.N_B_STATE = 3; task.S_B_STATE = TN_Task.GetStateStr(task.N_B_STATE); task.T_END_TIME = DateTime.Now; db.Updateable(task).UpdateColumns(it => new { it.N_B_STATE, it.S_B_STATE, it.T_END_TIME }).ExecuteCommand(); } } internal static void Fail(TN_Task task) { var db = new SqlHelper<TN_Task>().GetInstance(); if (task != null) { //判断有没有取货完成,没有就变成失败。有取货完成默认完成了(跟据项目而定,有些项目人工拉走了也没有放到终点)。 task.N_B_STATE = 4; task.S_B_STATE = TN_Task.GetStateStr(task.N_B_STATE); db.Updateable(task).UpdateColumns(it => new { it.N_B_STATE, it.S_B_STATE }).ExecuteCommand(); } } internal static bool AddActionRecord(string no, int state, string forkliftNo, string extData) { var db = new SqlHelper<TN_Task_Action>().GetInstance(); var action = new TN_Task_Action() { N_ACTION_CODE = state, S_TASK_CODE = no, S_EQ_CODE = forkliftNo, S_EQ_TYPE = "agv", S_DATA = extData }; return db.Insertable(action).ExecuteCommand() > 0; } internal static List<TN_Task> GetWaitingTaskList() { var db = new SqlHelper<object>().GetInstance(); return db.Queryable<TN_Task>().Where(a => a.N_B_STATE == 0 && (a.S_B_STATE == "等待" || a.S_B_STATE == "待推送")).ToList(); } } public class CreateTasks { public string from { set; get; } public string to { set; get; } public string taskType { set; get; } public int pri { set; get; } public string cntrInfo { set; get; } } } wms/WMSHelper.cscopy from ServiceCore/DebugCore.cs copy to wms/WMSHelper.cs
File was copied from ServiceCore/DebugCore.cs @@ -4,8 +4,8 @@ using System.Text; using System.Threading.Tasks; namespace HH.WCS.Mobox3.DSZSH.ServiceCore { public class DebugCore { namespace HH.WCS.Mobox3.DSZSH.wms { public class WMSHelper { } }