| | |
| | | { |
| | | "version": "1.0.0", |
| | | "lastScanned": 1774488038530, |
| | | "lastScanned": 1775442733141, |
| | | "projectRoot": "D:\\Git\\ShanMeiXinNengYuan", |
| | | "techStack": { |
| | | "languages": [], |
| | |
| | | "path": "Code", |
| | | "purpose": null, |
| | | "fileCount": 0, |
| | | "lastAccessed": 1774488038511, |
| | | "lastAccessed": 1775442733121, |
| | | "keyFiles": [] |
| | | }, |
| | | "项ç®èµæ": { |
| | | "path": "项ç®èµæ", |
| | | "purpose": null, |
| | | "fileCount": 0, |
| | | "lastAccessed": 1774488038512, |
| | | "lastAccessed": 1775442733121, |
| | | "keyFiles": [] |
| | | } |
| | | }, |
| | | "hotPaths": [ |
| | | { |
| | | "path": "Code\\WMS\\WIDESEA_WMSServer\\WIDESEA_StockService\\StockSerivce.cs", |
| | | "accessCount": 14, |
| | | "lastAccessed": 1774492937086, |
| | | "type": "file" |
| | | }, |
| | | { |
| | | "path": "Code\\WMS\\WIDESEA_WMSServer\\WIDESEA_WMSServer\\appsettings.json", |
| | | "accessCount": 5, |
| | | "lastAccessed": 1774490361799, |
| | | "type": "file" |
| | | }, |
| | | { |
| | | "path": "Code\\WMS\\WIDESEA_WMSServer\\WIDESEA_WMSServer\\Program.cs", |
| | | "accessCount": 3, |
| | | "lastAccessed": 1774488093580, |
| | | "type": "file" |
| | | }, |
| | | { |
| | | "path": "Code\\WMS\\WIDESEA_WMSServer\\WIDESEA_WMSServer\\WIDESEA_WMSServer.csproj", |
| | | "accessCount": 1, |
| | | "lastAccessed": 1774488065335, |
| | | "type": "file" |
| | | }, |
| | | { |
| | | "path": "Code\\WMS\\WIDESEA_WMSServer\\WIDESEA_StockService\\StockViewService.cs", |
| | | "accessCount": 1, |
| | | "lastAccessed": 1774492577060, |
| | | "type": "file" |
| | | }, |
| | | { |
| | | "path": "Code\\WMS\\WIDESEA_WMSServer\\WIDESEA_StockService\\StockInfoService.cs", |
| | | "accessCount": 1, |
| | | "lastAccessed": 1774492577097, |
| | | "type": "file" |
| | | }, |
| | | { |
| | | "path": "Code\\WMS\\WIDESEA_WMSServer\\WIDESEA_StockService\\StockInfoDetailService.cs", |
| | | "accessCount": 1, |
| | | "lastAccessed": 1774492577122, |
| | | "type": "file" |
| | | }, |
| | | { |
| | | "path": "Code\\WMS\\WIDESEA_WMSServer\\WIDESEA_Core\\BaseServices\\ServiceBase.cs", |
| | | "accessCount": 1, |
| | | "lastAccessed": 1774492577619, |
| | | "type": "file" |
| | | }, |
| | | { |
| | | "path": "Code\\WMS\\WIDESEA_WMSServer\\WIDESEA_IStockService\\IStockInfoService.cs", |
| | | "accessCount": 1, |
| | | "lastAccessed": 1774492782997, |
| | | "type": "file" |
| | | } |
| | | ], |
| | | "hotPaths": [], |
| | | "userDirectives": [] |
| | | } |
| | |
| | | }, |
| | | { |
| | | title: "ä»»å¡ç¶æ", |
| | | field: "taskState", |
| | | field: "taskStatus", |
| | | type: "selectList", |
| | | dataKey: "taskState", |
| | | data: [], |
| | |
| | | bind: { key: "taskType", data: [] }, |
| | | }, |
| | | { |
| | | field: "taskState", |
| | | field: "taskStatus", |
| | | title: "ä»»å¡ç¶æ", |
| | | type: "int", |
| | | width: 150, |
| | |
| | | using System; |
| | | using Magicodes.ExporterAndImporter.Core; |
| | | using SqlSugar; |
| | | using System; |
| | | using System.Collections.Generic; |
| | | using System.Linq; |
| | | using System.Text; |
| | |
| | | /// <summary> |
| | | /// WMSä»»å¡ä¸»é® |
| | | /// </summary> |
| | | public int Id { get; set; } |
| | | public int Id { get; set; } |
| | | |
| | | /// <summary> |
| | | /// ä»»å¡å· |
| | | /// </summary> |
| | | public int TaskNum { get; set; } |
| | | public int TaskNum { get; set; } |
| | | |
| | | /// <summary> |
| | | /// æçå· |
| | | /// </summary> |
| | | public string PalletCode { get; set; } |
| | | public string PalletCode { get; set; } |
| | | |
| | | /// <summary> |
| | | /// å··éå· |
| | |
| | | /// <summary> |
| | | /// ä»»å¡ç±»å |
| | | /// </summary> |
| | | public int TaskType { get; set; } |
| | | public int TaskType { get; set; } |
| | | |
| | | /// <summary> |
| | | /// ä»»å¡ç¶æ |
| | |
| | | /// <summary> |
| | | /// èµ·ç¹ |
| | | /// </summary> |
| | | public string SourceAddress { get; set; } |
| | | public string SourceAddress { get; set; } |
| | | |
| | | /// <summary> |
| | | /// ç»ç¹ |
| | | /// </summary> |
| | | public string TargetAddress { get; set; } |
| | | public string TargetAddress { get; set; } |
| | | |
| | | /// <summary> |
| | | /// å½åä½ç½® |
| | | /// </summary> |
| | | public string CurrentAddress { get; set; } |
| | | |
| | | /// <summary> |
| | | /// ä¸ä¸å°å |
| | | /// </summary> |
| | | public string NextAddress { get; set; } |
| | | |
| | | /// <summary> |
| | | /// ä¼å
级 |
| | | /// </summary> |
| | | public int Grade { get; set; } |
| | | public int Grade { get; set; } |
| | | |
| | | /// <summary> |
| | | /// |
| | | /// </summary> |
| | | public int WarehouseId { get; set; } |
| | | |
| | | /// <summary> |
| | | /// |
| | | /// </summary> |
| | | public string AGVArea { get; set; } |
| | | |
| | | /// <summary> |
| | | /// |
| | | /// </summary> |
| | | public int PalletType { get; set; } |
| | | |
| | | |
| | | |
| | | } |
| | | } |
| | | } |
| | |
| | | } |
| | | #endregion |
| | | |
| | | #region TaskRobotStatusEnum |
| | | |
| | | { |
| | | Type type = typeof(TaskRobotStatusEnum); |
| | | List<int> enums = Enum.GetValues(typeof(TaskRobotStatusEnum)).Cast<int>().ToList(); |
| | | int index = 0; |
| | | foreach (var item in enums) |
| | | { |
| | | FieldInfo? fieldInfo = typeof(TaskRobotStatusEnum).GetField(((TaskRobotStatusEnum)item).ToString()); |
| | | DescriptionAttribute? description = fieldInfo.GetCustomAttribute<DescriptionAttribute>(); |
| | | if (description != null) |
| | | { |
| | | data.Add(new { key = item.ToString(), value = description.Description }); |
| | | } |
| | | else |
| | | { |
| | | data.Add(new { key = item.ToString(), value = item.ToString() }); |
| | | } |
| | | index++; |
| | | } |
| | | } |
| | | #endregion |
| | | result = new VueDictionaryDTO { DicNo = key, Config = "", Data = data }; |
| | | } |
| | | break; |
| | |
| | | result = new VueDictionaryDTO { DicNo = key, Config = "", Data = data }; |
| | | } |
| | | break; |
| | | case "dispatchId": |
| | | case "dispatchId": |
| | | { |
| | | Type type = typeof(IJob); |
| | | var basePath = AppContext.BaseDirectory; |
| | |
| | | } |
| | | } |
| | | } |
| | | } |
| | | } |
| | |
| | | "DBType": "SqlServer", |
| | | //è¿æ¥å符串 |
| | | "ConnectionString": "Data Source=.;Initial Catalog=WIDESEAWCS_ShanMei;User ID=sa;Password=P@ssw0rd;Integrated Security=False;Connect Timeout=30;Encrypt=False;TrustServerCertificate=False;ApplicationIntent=ReadWrite;MultiSubnetFailover=False", |
| | | //"ConnectionString": "Data Source=.;Initial Catalog=WIDESEAWCS_ShanMei;User ID=sa;Password=123456;Integrated Security=False;Connect Timeout=30;Encrypt=False;TrustServerCertificate=False;ApplicationIntent=ReadWrite;MultiSubnetFailover=False", |
| | | |
| | | //è·¨å |
| | | "Cors": { |
| | |
| | | "MaxMemoryPolicy": "allkeys-lru" //å
åæ·æ±°çç¥ï¼allkeys-lru, volatile-lru, noevictionç |
| | | } |
| | | } |
| | | } |
| | | } |
| | |
| | | InitializeTaskOnReceive(task, item); |
| | | tasks.Add(task); |
| | | } |
| | | // TOOD: è¿éæ³¨ææ·»å é误è¦è¿åé误 |
| | | BaseDal.AddData(tasks); |
| | | |
| | | _taskExecuteDetailService.AddTaskExecuteDetail(tasks.Select(x => x.TaskNum).ToList(), "æ¥æ¶WMSä»»å¡"); |
| | |
| | | [DataLength(22)] |
| | | public string Barcode { get; set; } |
| | | } |
| | | } |
| | | } |
| | |
| | | public class ConveyorLineTargetAddressSelector |
| | | { |
| | | /// <summary> |
| | | /// æææºå称常é |
| | | /// 设å¤å±çº§ï¼ä¸å±/ä¸å±ï¼ |
| | | /// </summary> |
| | | private const string ConstraintMachineName = "æææº"; |
| | | /// <remarks> |
| | | /// ç¨äºåºåæææºåææéæºçä¸å±å·¥ä½åä¸å±å·¥ä½ã |
| | | /// å
¥åºä»»å¡å¯¹åºä¸å±ï¼MaterialRequestUpperï¼ï¼åºåºä»»å¡å¯¹åºä¸å±ï¼MaterialRequestLowerï¼ã |
| | | /// </remarks> |
| | | private enum Layer |
| | | { |
| | | /// <summary> |
| | | /// ä¸å±å·¥ä½ |
| | | /// </summary> |
| | | Upper, |
| | | |
| | | /// <summary> |
| | | /// ä¸å±å·¥ä½ |
| | | /// </summary> |
| | | Lower |
| | | } |
| | | |
| | | /// <summary> |
| | | /// ææéæºå称常é |
| | | /// ç®æ 设å¤ç±»åæä¸¾ |
| | | /// </summary> |
| | | private const string PinMachineName = "ææéæº"; |
| | | /// <remarks> |
| | | /// ç¨äºæ ¹æ®ç®æ å°åç¼ç è¯å«éè¦å¯¹æ¥ç设å¤ç±»åã |
| | | /// </remarks> |
| | | private enum TargetDeviceType |
| | | { |
| | | /// <summary> |
| | | /// æ ææè®¾å¤ï¼å°åä¸å¨å·²ç¥èå´å
ï¼ |
| | | /// </summary> |
| | | None, |
| | | |
| | | /// <summary> |
| | | /// æææº |
| | | /// </summary> |
| | | /// <remarks> |
| | | /// è´è´£åºå®/约æçµæ± æçç设å¤ï¼æä¸ä¸ä¸¤å±ã |
| | | /// </remarks> |
| | | ConstraintMachine, |
| | | |
| | | /// <summary> |
| | | /// ææéæº |
| | | /// </summary> |
| | | /// <remarks> |
| | | /// è´è´£æéåæéæä½ç设å¤ï¼æä¸ä¸ä¸¤å±ã |
| | | /// </remarks> |
| | | PinMachine |
| | | } |
| | | |
| | | /// <summary> |
| | | /// æææºå¯¹åºçç¹ä½ç¼ç å表 |
| | | /// æææºå¯¹åºçç¹ä½ç¼ç éå |
| | | /// </summary> |
| | | /// <remarks> |
| | | /// å½ç®æ å°åå¨è¿äºç¼ç 䏿¶ï¼è¡¨ç¤ºéè¦ä¸æææºäº¤äºã |
| | | /// ä½¿ç¨ HashSet ä¿è¯ O(1) ç Contains æ¥æ¾æ§è½ã |
| | | /// </remarks> |
| | | private static readonly List<string> ConstraintMachineCodes = new List<string> { "10180", "20090" }; |
| | | private static readonly HashSet<string> ConstraintMachineCodes = new HashSet<string> { "10180", "20090" }; |
| | | |
| | | /// <summary> |
| | | /// ææéæºå¯¹åºçç¹ä½ç¼ç å表 |
| | | /// ææéæºå¯¹åºçç¹ä½ç¼ç éå |
| | | /// </summary> |
| | | /// <remarks> |
| | | /// å½ç®æ å°åå¨è¿äºç¼ç 䏿¶ï¼è¡¨ç¤ºéè¦ä¸ææéæºäº¤äºã |
| | | /// ä½¿ç¨ HashSet ä¿è¯ O(1) ç Contains æ¥æ¾æ§è½ã |
| | | /// </remarks> |
| | | private static readonly List<string> PinMachineCodes = new List<string> { "10190", "20100" }; |
| | | private static readonly HashSet<string> PinMachineCodes = new HashSet<string> { "10190", "20100" }; |
| | | |
| | | /// <summary> |
| | | /// ç®æ å°åå°è®¾å¤ç±»åçæ å° |
| | | /// </summary> |
| | | /// <remarks> |
| | | /// éè¿åä¸åå
¸å®ç° O(1) æ¥æ¾ï¼æ¿ä»£åå
åå«ç¨ä¸¤ä¸ª List + Contains + if/else if çåæ³ã |
| | | /// Key: ç®æ å°åç¼ç ï¼Value: 对åºç设å¤ç±»åã |
| | | /// </remarks> |
| | | private static readonly Dictionary<string, TargetDeviceType> AddressToDeviceType = new Dictionary<string, TargetDeviceType> |
| | | { |
| | | // æææºç两个ç¹ä½ç¼ç 齿 å°å° ConstraintMachine ç±»å |
| | | { "10180", TargetDeviceType.ConstraintMachine }, |
| | | { "20090", TargetDeviceType.ConstraintMachine }, |
| | | // ææéæºç两个ç¹ä½ç¼ç 齿 å°å° PinMachine ç±»å |
| | | { "10190", TargetDeviceType.PinMachine }, |
| | | { "20100", TargetDeviceType.PinMachine } |
| | | }; |
| | | |
| | | /// <summary> |
| | | /// æ¥å¿è®°å½å¨ |
| | | /// </summary> |
| | | /// <remarks> |
| | | /// éè¿ Microsoft.Extensions.Logging æ¥å£æ³¨å
¥ï¼ç¨äºç»æåæ¥å¿è¾åºã |
| | | /// </remarks> |
| | | private readonly ILogger _logger; |
| | | |
| | | /// <summary> |
| | | /// æé 彿° |
| | | /// </summary> |
| | | /// <param name="logger">æ¥å¿è®°å½å¨</param> |
| | | /// <param name="logger">æ¥å¿è®°å½å¨ï¼ç±ä¾èµæ³¨å
¥å®¹å¨èªå¨æ³¨å
¥</param> |
| | | public ConveyorLineTargetAddressSelector(ILogger logger) |
| | | { |
| | | _logger = logger; |
| | | _logger = logger; // ä¿åæ¥å¿è®°å½å¨å®ä¾ï¼ä¾åç»æ¹æ³ä½¿ç¨ |
| | | } |
| | | |
| | | /// <summary> |
| | | /// å¤çå
¥åºåºæ¯çä¸ä¸å°åè¯·æ± |
| | | /// </summary> |
| | | /// <remarks> |
| | | /// å½å
¥åºä»»å¡æ§è¡å°æä¸ªä½ç½®æ¶è°ç¨æ¤æ¹æ³ã |
| | | /// å¤æç®æ è®¾å¤æ¯å¦éè¦ç©ææå¯ä»¥åºæã |
| | | /// å
¥åºä»»å¡å°è¾¾æä¸ªä½ç½®æ¶è°ç¨æ¤æ¹æ³ï¼å¤æç®æ è®¾å¤æ¯å¦éè¦ç©æã |
| | | /// å
¥åºå¯¹åºä¸å±å·¥ä½ï¼Layer.Upperï¼ï¼å ä¸ºç©æä»ä¸å±è¿å
¥ä»åºã |
| | | /// </remarks> |
| | | /// <param name="conveyorLine">è¾é线设å¤å¯¹è±¡</param> |
| | | /// <param name="nextAddress">ä¸ä¸å°å/ç®æ 设å¤ç¼ç </param> |
| | | /// <param name="childDeviceCode">å½åå设å¤ç¼ç </param> |
| | | /// <param name="conveyorLine">è¾é线设å¤å¯¹è±¡ï¼ç¨äºåå
¥ç®æ å°åå ACK ä¿¡å·</param> |
| | | /// <param name="nextAddress">ä¸ä¸å°å/ç®æ 设å¤ç¼ç ï¼ç¨äºè¯å«ç®æ 设å¤ç±»å</param> |
| | | /// <param name="childDeviceCode">å½åå设å¤ç¼ç ï¼ç¨äºç²¾ç¡®å®ä½åå
¥åªä¸ªå设å¤</param> |
| | | public void HandleInboundNextAddress(CommonConveyorLine conveyorLine, string nextAddress, string childDeviceCode) |
| | | { |
| | | _logger.LogDebug("HandleInboundNextAddressï¼å
¥åºä¸ä¸å°åï¼å设å¤: {ChildDeviceCode}ï¼ç®æ å°å: {NextAddress}", childDeviceCode, nextAddress); |
| | | QuartzLogger.Debug($"HandleInboundNextAddressï¼å
¥åºä¸ä¸å°åï¼å设å¤: {childDeviceCode}ï¼ç®æ å°å: {nextAddress}", conveyorLine.DeviceCode); |
| | | // è°ç¨éç¨å¤çæ¹æ³ï¼isUpper = true 表示å¤çä¸å± |
| | | HandleDeviceRequest(conveyorLine, nextAddress, childDeviceCode, isUpper: true); |
| | | // è®°å½å
¥åºåºæ¯çè°è¯æ¥å¿ï¼å
å«å设å¤åç®æ å°åä¿¡æ¯ |
| | | WriteDebug(conveyorLine, "å
¥åºä¸ä¸å°å", childDeviceCode, nextAddress); |
| | | // å§æéç¨å¤çæ¹æ³ï¼å
¥åºå¯¹åºä¸å±ï¼isUpper: trueï¼ |
| | | HandleDeviceRequest(conveyorLine, nextAddress, childDeviceCode, Layer.Upper); |
| | | } |
| | | |
| | | /// <summary> |
| | | /// å¤çåºåºåºæ¯çä¸ä¸å°åè¯·æ± |
| | | /// </summary> |
| | | /// <remarks> |
| | | /// å½åºåºä»»å¡æ§è¡å°æä¸ªä½ç½®æ¶è°ç¨æ¤æ¹æ³ã |
| | | /// å¤æç®æ è®¾å¤æ¯å¦éè¦ç©ææå¯ä»¥åºæã |
| | | /// åºåºä»»å¡å°è¾¾æä¸ªä½ç½®æ¶è°ç¨æ¤æ¹æ³ï¼å¤æç®æ è®¾å¤æ¯å¦éè¦åºæã |
| | | /// åºåºå¯¹åºä¸å±å·¥ä½ï¼Layer.Lowerï¼ï¼å ä¸ºç©æä»ä¸å±ç¦»å¼ä»åºã |
| | | /// </remarks> |
| | | /// <param name="conveyorLine">è¾é线设å¤å¯¹è±¡</param> |
| | | /// <param name="nextAddress">ä¸ä¸å°å/ç®æ 设å¤ç¼ç </param> |
| | | /// <param name="childDeviceCode">å½åå设å¤ç¼ç </param> |
| | | /// <param name="conveyorLine">è¾é线设å¤å¯¹è±¡ï¼ç¨äºåå
¥ç®æ å°åå ACK ä¿¡å·</param> |
| | | /// <param name="nextAddress">ä¸ä¸å°å/ç®æ 设å¤ç¼ç ï¼ç¨äºè¯å«ç®æ 设å¤ç±»å</param> |
| | | /// <param name="childDeviceCode">å½åå设å¤ç¼ç ï¼ç¨äºç²¾ç¡®å®ä½åå
¥åªä¸ªå设å¤</param> |
| | | public void HandleOutboundNextAddress(CommonConveyorLine conveyorLine, string nextAddress, string childDeviceCode) |
| | | { |
| | | _logger.LogDebug("HandleOutboundNextAddressï¼åºåºä¸ä¸å°åï¼å设å¤: {ChildDeviceCode}ï¼ç®æ å°å: {NextAddress}", childDeviceCode, nextAddress); |
| | | QuartzLogger.Debug($"HandleOutboundNextAddressï¼åºåºä¸ä¸å°åï¼å设å¤: {childDeviceCode}ï¼ç®æ å°å: {nextAddress}", conveyorLine.DeviceCode); |
| | | // è°ç¨éç¨å¤çæ¹æ³ï¼isUpper = false 表示å¤çä¸å± |
| | | HandleDeviceRequest(conveyorLine, nextAddress, childDeviceCode, isUpper: false); |
| | | // è®°å½åºåºåºæ¯çè°è¯æ¥å¿ï¼å
å«å设å¤åç®æ å°åä¿¡æ¯ |
| | | WriteDebug(conveyorLine, "åºåºä¸ä¸å°å", childDeviceCode, nextAddress); |
| | | // å§æéç¨å¤çæ¹æ³ï¼åºåºå¯¹åºä¸å±ï¼isUpper: falseï¼ |
| | | HandleDeviceRequest(conveyorLine, nextAddress, childDeviceCode, Layer.Lower); |
| | | } |
| | | |
| | | /// <summary> |
| | | /// éç¨è®¾å¤è¯·æ±å¤çæ¹æ³ |
| | | /// æ ¹æ®ç®æ å°åç±»åååå°å¯¹åºè®¾å¤å¤ç |
| | | /// </summary> |
| | | /// <remarks> |
| | | /// æ ¹æ®ç®æ å°åç±»åï¼æææº/ææéæºï¼è°ç¨ç¸åºçå¤çé»è¾ã |
| | | /// å¤çä¸ä¸å±è®¾å¤çç©æè¯·æ±ååºæåè°ã |
| | | /// éè¿ AddressToDeviceType åå
¸å°ç®æ å°åæ å°å°è®¾å¤ç±»åï¼ |
| | | /// ç¶åååå°å¯¹åºçä¸ç¨å¤çæ¹æ³ï¼HandleConstraintMachine / HandlePinMachineï¼ã |
| | | /// å¦æç®æ å°åä¸å¨å·²ç¥æ å°è¡¨ä¸ï¼ç´æ¥è¿åï¼ä¸åä»»ä½å¤çã |
| | | /// </remarks> |
| | | /// <param name="conveyorLine">è¾é线设å¤å¯¹è±¡</param> |
| | | /// <param name="nextAddress">ä¸ä¸å°å/ç®æ 设å¤ç¼ç </param> |
| | | /// <param name="childDeviceCode">å½åå设å¤ç¼ç </param> |
| | | /// <param name="isUpper">æ¯å¦å¤çä¸å±ï¼true=ä¸å±ï¼false=ä¸å±ï¼</param> |
| | | private void HandleDeviceRequest(CommonConveyorLine conveyorLine, string nextAddress, string childDeviceCode, bool isUpper) |
| | | /// <param name="conveyorLine">è¾é线设å¤å¯¹è±¡ï¼ä¼ éå°å
·ä½è®¾å¤å¤çæ¹æ³</param> |
| | | /// <param name="nextAddress">ç®æ 设å¤ç¼ç ï¼éè¿åå
¸æ¥æ¾è¯å«è®¾å¤ç±»å</param> |
| | | /// <param name="childDeviceCode">å设å¤ç¼ç ï¼ä¼ éå°å
·ä½è®¾å¤å¤çæ¹æ³</param> |
| | | /// <param name="layer">设å¤å±çº§ï¼ä¸å±æä¸å±ï¼ï¼å³å®è¯»ååªç»è¯·æ±æ å¿</param> |
| | | private void HandleDeviceRequest(CommonConveyorLine conveyorLine, string nextAddress, string childDeviceCode, Layer layer) |
| | | { |
| | | // è·åå
¨å±è®¾å¤å表 |
| | | var devices = Storage.Devices; |
| | | |
| | | // å¤æç®æ 设å¤ç±»å |
| | | if (ConstraintMachineCodes.Contains(nextAddress)) |
| | | // éè¿åå
¸æ¥æ¾ç®æ å°å对åºç设å¤ç±»åï¼å¦ææ¾ä¸å°å deviceType 为 None |
| | | if (!AddressToDeviceType.TryGetValue(nextAddress, out var deviceType) || deviceType == TargetDeviceType.None) |
| | | { |
| | | // æææºå¤ç忝 |
| | | // æ¥æ¾æææºè®¾å¤ |
| | | ConstraintMachine? constraint = devices.OfType<ConstraintMachine>().FirstOrDefault(d => d.DeviceName == ConstraintMachineName); |
| | | if (constraint == null) |
| | | { |
| | | _logger.LogDebug("HandleDeviceRequestï¼æªæ¾å°æææºè®¾å¤"); |
| | | QuartzLogger.Debug("HandleDeviceRequestï¼æªæ¾å°æææºè®¾å¤", conveyorLine.DeviceCode); |
| | | // æªæ¾å°æææºè®¾å¤ï¼ç´æ¥è¿å |
| | | return; |
| | | } |
| | | |
| | | // å¤çæææºçè¯·æ± |
| | | ProcessDeviceRequest( |
| | | conveyorLine, |
| | | childDeviceCode, |
| | | // è·åç©æè¯·æ±æ å¿ï¼ä¸å±æä¸å±ï¼ |
| | | getMaterialRequest: () => isUpper |
| | | ? constraint.GetValue<ConstraintMachineDBName, short>(ConstraintMachineDBName.MaterialRequestUpper) != 0 |
| | | : constraint.GetValue<ConstraintMachineDBName, short>(ConstraintMachineDBName.MaterialRequestLower) != 0, |
| | | // è·ååºæè¯·æ±æ å¿ï¼ä¸å±æä¸å±ï¼ |
| | | getOutputRequest: () => isUpper |
| | | ? constraint.GetValue<ConstraintMachineDBName, short>(ConstraintMachineDBName.OutputRequestUpper) != 0 |
| | | : constraint.GetValue<ConstraintMachineDBName, short>(ConstraintMachineDBName.OutputRequestLower) != 0, |
| | | // 设置è¾åºå°±ç»ªæ å¿ï¼ä¸å±æä¸å±ï¼ |
| | | setOutputReady: outputReq => |
| | | { |
| | | if (isUpper) |
| | | { |
| | | constraint.SetValue(ConstraintMachineDBName.ConstraintTrayOutputReadyUpper, outputReq ? 1 : 0); |
| | | } |
| | | else |
| | | { |
| | | constraint.SetValue(ConstraintMachineDBName.ConstraintTrayOutputReadyLower, outputReq ? 1 : 0); |
| | | } |
| | | }, |
| | | "æææº"); |
| | | // ç®æ å°åä¸å¨å·²ç¥æ å°è¡¨ä¸ï¼ç´æ¥è¿åï¼å¯è½æ¯å
¶ä»ç±»å设å¤ï¼ |
| | | return; |
| | | } |
| | | else if (PinMachineCodes.Contains(nextAddress)) |
| | | |
| | | // æ ¹æ®è¯å«åºç设å¤ç±»åååå°å¯¹åºçå¤çæ¹æ³ |
| | | switch (deviceType) |
| | | { |
| | | // ææéæºå¤ç忝 |
| | | // æ¥æ¾ææéæºè®¾å¤ |
| | | PinMachine? pinMachine = devices.OfType<PinMachine>().FirstOrDefault(d => d.DeviceName == PinMachineName); |
| | | if (pinMachine == null) |
| | | { |
| | | _logger.LogDebug("HandleDeviceRequestï¼æªæ¾å°ææéæºè®¾å¤"); |
| | | QuartzLogger.Debug("HandleDeviceRequestï¼æªæ¾å°ææéæºè®¾å¤", conveyorLine.DeviceCode); |
| | | return; |
| | | } |
| | | case TargetDeviceType.ConstraintMachine: |
| | | // æææºå¤ç忝ï¼è·åæææºå®ä¾å¹¶å¤çå
¶ä¸ä¸å±è¯·æ± |
| | | HandleConstraintMachine(conveyorLine, childDeviceCode, layer); |
| | | break; // å¤ç宿¯ï¼è·³åº switch |
| | | |
| | | // å¤çææéæºçè¯·æ± |
| | | ProcessDeviceRequest( |
| | | conveyorLine, |
| | | childDeviceCode, |
| | | // è·åç©æè¯·æ±æ å¿ï¼ä¸å±æä¸å±ï¼ |
| | | getMaterialRequest: () => isUpper |
| | | ? pinMachine.GetValue<PinMachineDBName, short>(PinMachineDBName.MaterialRequestUpper) != 0 |
| | | : pinMachine.GetValue<PinMachineDBName, short>(PinMachineDBName.MaterialRequestLower) != 0, |
| | | // è·ååºæè¯·æ±æ å¿ï¼ä¸å±æä¸å±ï¼ |
| | | getOutputRequest: () => isUpper |
| | | ? pinMachine.GetValue<PinMachineDBName, short>(PinMachineDBName.OutputRequestUpper) != 0 |
| | | : pinMachine.GetValue<PinMachineDBName, short>(PinMachineDBName.OutputRequestLower) != 0, |
| | | // 设置è¾åºå°±ç»ªæ å¿ï¼ä¸å±æä¸å±ï¼ |
| | | setOutputReady: outputReq => |
| | | { |
| | | if (isUpper) |
| | | { |
| | | pinMachine.SetValue(PinMachineDBName.PlugPinTrayOutputReadyUpper, outputReq ? 1 : 0); |
| | | } |
| | | else |
| | | { |
| | | pinMachine.SetValue(PinMachineDBName.PlugPinTrayOutputReadyLower, outputReq ? 1 : 0); |
| | | } |
| | | }, |
| | | "ææéæº"); |
| | | case TargetDeviceType.PinMachine: |
| | | // ææéæºå¤ç忝ï¼è·åææéæºå®ä¾å¹¶å¤çå
¶ä¸ä¸å±è¯·æ± |
| | | HandlePinMachine(conveyorLine, childDeviceCode, layer); |
| | | break; // å¤ç宿¯ï¼è·³åº switch |
| | | } |
| | | } |
| | | |
| | | /// <summary> |
| | | /// å¤çæææºçç©æ/åºæè¯·æ± |
| | | /// </summary> |
| | | /// <remarks> |
| | | /// æ¥æ¾æææºè®¾å¤ï¼è·åå½åå±çº§çç©æè¯·æ±ååºæè¯·æ±ç¶æï¼ |
| | | /// ç¶åè°ç¨éç¨å¤çé»è¾ ProcessDeviceRequestã |
| | | /// </remarks> |
| | | /// <param name="conveyorLine">è¾é线设å¤å¯¹è±¡ï¼ç¨äºéç¥ç®æ å°åå ACK</param> |
| | | /// <param name="childDeviceCode">å设å¤ç¼ç ï¼ç¨äºç²¾ç¡®å®ä½</param> |
| | | /// <param name="layer">设å¤å±çº§ï¼å³å®è¯»åä¸å±è¿æ¯ä¸å±çè¯·æ±æ å¿</param> |
| | | private void HandleConstraintMachine(CommonConveyorLine conveyorLine, string childDeviceCode, Layer layer) |
| | | { |
| | | // ä»å
¨å±è®¾å¤åè¡¨ä¸æ¥æ¾å为"æææº"çæææºè®¾å¤å®ä¾ |
| | | var constraint = FindDevice<ConstraintMachine>("æææº"); |
| | | if (constraint == null) |
| | | { |
| | | // æªæ¾å°æææºè®¾å¤ï¼å·²å¨ FindDevice ä¸è®°å½æ¥å¿ï¼æ¤å¤ç´æ¥è¿å |
| | | return; |
| | | } |
| | | |
| | | // è·åå½åå±çº§ï¼ä¸å±/ä¸å±ï¼çç©æè¯·æ±æ å¿ï¼éé¶è¡¨ç¤ºè®¾å¤éè¦ç©æ |
| | | bool materialRequest = GetConstraintFlag(constraint, layer, isMaterial: true); |
| | | // è·åå½åå±çº§ï¼ä¸å±/ä¸å±ï¼çåºæè¯·æ±æ å¿ï¼éé¶è¡¨ç¤ºè®¾å¤æè´§è¦åº |
| | | bool outputRequest = GetConstraintFlag(constraint, layer, isMaterial: false); |
| | | |
| | | // æé 设置è¾åºå°±ç»ªæ å¿çå§æï¼æ ¹æ®å±çº§åå
¥ Upper æ Lower 对åºçå¯åå¨ï¼ |
| | | Action<bool> setOutputReady = outputReady => |
| | | SetConstraintOutputReady(constraint, layer, outputReady); |
| | | |
| | | // è°ç¨éç¨è¯·æ±å¤çé»è¾ï¼ä¼ å
¥è®¾å¤ç±»åæè¿°ç¨äºæ¥å¿è®°å½ |
| | | ProcessDeviceRequest(conveyorLine, childDeviceCode, materialRequest, outputRequest, setOutputReady, "æææº"); |
| | | } |
| | | |
| | | /// <summary> |
| | | /// å¤çææéæºçç©æ/åºæè¯·æ± |
| | | /// </summary> |
| | | /// <remarks> |
| | | /// æ¥æ¾ææéæºè®¾å¤ï¼è·åå½åå±çº§çç©æè¯·æ±ååºæè¯·æ±ç¶æï¼ |
| | | /// ç¶åè°ç¨éç¨å¤çé»è¾ ProcessDeviceRequestã |
| | | /// </remarks> |
| | | /// <param name="conveyorLine">è¾é线设å¤å¯¹è±¡ï¼ç¨äºéç¥ç®æ å°åå ACK</param> |
| | | /// <param name="childDeviceCode">å设å¤ç¼ç ï¼ç¨äºç²¾ç¡®å®ä½</param> |
| | | /// <param name="layer">设å¤å±çº§ï¼å³å®è¯»åä¸å±è¿æ¯ä¸å±çè¯·æ±æ å¿</param> |
| | | private void HandlePinMachine(CommonConveyorLine conveyorLine, string childDeviceCode, Layer layer) |
| | | { |
| | | // ä»å
¨å±è®¾å¤åè¡¨ä¸æ¥æ¾å为"ææéæº"çææéæºè®¾å¤å®ä¾ |
| | | var pinMachine = FindDevice<PinMachine>("ææéæº"); |
| | | if (pinMachine == null) |
| | | { |
| | | // æªæ¾å°ææéæºè®¾å¤ï¼å·²å¨ FindDevice ä¸è®°å½æ¥å¿ï¼æ¤å¤ç´æ¥è¿å |
| | | return; |
| | | } |
| | | |
| | | // è·åå½åå±çº§ï¼ä¸å±/ä¸å±ï¼çç©æè¯·æ±æ å¿ï¼éé¶è¡¨ç¤ºè®¾å¤éè¦ç©æ |
| | | bool materialRequest = GetPinMachineFlag(pinMachine, layer, isMaterial: true); |
| | | // è·åå½åå±çº§ï¼ä¸å±/ä¸å±ï¼çåºæè¯·æ±æ å¿ï¼éé¶è¡¨ç¤ºè®¾å¤æè´§è¦åº |
| | | bool outputRequest = GetPinMachineFlag(pinMachine, layer, isMaterial: false); |
| | | |
| | | // æé 设置è¾åºå°±ç»ªæ å¿çå§æï¼æ ¹æ®å±çº§åå
¥ Upper æ Lower 对åºçå¯åå¨ï¼ |
| | | Action<bool> setOutputReady = outputReady => |
| | | SetPinMachineOutputReady(pinMachine, layer, outputReady); |
| | | |
| | | // è°ç¨éç¨è¯·æ±å¤çé»è¾ï¼ä¼ å
¥è®¾å¤ç±»åæè¿°ç¨äºæ¥å¿è®°å½ |
| | | ProcessDeviceRequest(conveyorLine, childDeviceCode, materialRequest, outputRequest, setOutputReady, "ææéæº"); |
| | | } |
| | | |
| | | /// <summary> |
| | | /// æ¥æ¾æå®åç§°çè®¾å¤ |
| | | /// </summary> |
| | | /// <remarks> |
| | | /// ä»å
¨å±è®¾å¤å表 Storage.Devices ä¸éè¿è®¾å¤ç±»åååç§°æ¥æ¾è®¾å¤å®ä¾ã |
| | | /// è¿æ¯ä¸ä¸ªæ³åæ¹æ³ï¼å¯ä»¥éç¨äº ConstraintMachineãPinMachine çå¤ç§è®¾å¤ç±»åã |
| | | /// </remarks> |
| | | /// <typeparam name="T">设å¤ç±»åï¼å¿
é¡»æ¯å¼ç¨ç±»åï¼å¦ ConstraintMachineãPinMachineï¼</typeparam> |
| | | /// <param name="deviceName">设å¤åç§°ï¼ç¨äºç²¾ç¡®å¹é
设å¤ç DeviceName 屿§</param> |
| | | /// <returns>æ¾å°ç设å¤å®ä¾ï¼æªæ¾å°åè¿å null</returns> |
| | | private T? FindDevice<T>(string deviceName) where T : class |
| | | { |
| | | // OfType<T>() çéåºæå®ç±»åç设å¤ï¼FirstOrDefault æå称精确å¹é
|
| | | var device = Storage.Devices.OfType<T>().FirstOrDefault(d => GetDeviceName(d) == deviceName); |
| | | if (device == null) |
| | | { |
| | | // è®¾å¤æªæ¾å°æ¶è®°å½è°è¯æ¥å¿ï¼æ¹ä¾¿ææ¥é
ç½®é®é¢ |
| | | _logger.LogDebug("FindDeviceï¼æªæ¾å° {DeviceName}", deviceName); |
| | | } |
| | | return device; // å¯è½ä¸º nullï¼ç±è°ç¨æ¹è´è´£ null æ£æ¥ |
| | | } |
| | | |
| | | /// <summary> |
| | | /// éè¿å¤æè·åä»»æè®¾å¤çåç§° |
| | | /// </summary> |
| | | /// <remarks> |
| | | /// ä½¿ç¨ switch è¡¨è¾¾å¼æ ¹æ®è®¾å¤çå
·ä½ç±»åè·åå
¶ DeviceName 屿§ï¼ |
| | | /// é¿å
为æ¯ç§è®¾å¤ç±»åç¼åç¬ç«çå尿屿§è®¿é®ä»£ç ã |
| | | /// å½åæ¯æ ConstraintMachine å PinMachine 两ç§ç±»åã |
| | | /// </remarks> |
| | | /// <typeparam name="T">设å¤ç±»å</typeparam> |
| | | /// <param name="device">设å¤å®ä¾ï¼é空</param> |
| | | /// <returns>设å¤çåç§°å符串ï¼å¦æç±»åä¸å¹é
åè¿å空å符串</returns> |
| | | private static string GetDeviceName<T>(T device) where T : class |
| | | { |
| | | // 模å¼å¹é
ï¼æ ¹æ®è®¾å¤çå
·ä½è¿è¡æ¶ç±»åè¿å对åºç DeviceName |
| | | return device switch |
| | | { |
| | | ConstraintMachine cm => cm.DeviceName, // æææºè¿åå
¶è®¾å¤åç§° |
| | | PinMachine pm => pm.DeviceName, // ææéæºè¿åå
¶è®¾å¤åç§° |
| | | _ => string.Empty // æªç¥ç±»åè¿å空å符串ï¼ç论ä¸ä¸ä¼èµ°å°è¿éï¼ |
| | | }; |
| | | } |
| | | |
| | | /// <summary> |
| | | /// è·åæææºçè¯·æ±æ å¿ï¼ç©æè¯·æ±æåºæè¯·æ±ï¼ |
| | | /// </summary> |
| | | /// <remarks> |
| | | /// æ ¹æ® isMaterial åæ°å³å®è¯»åç©æè¯·æ±è¿æ¯åºæè¯·æ±å¯åå¨ï¼ |
| | | /// åæ ¹æ® layer åæ°å³å®è¯»åä¸å±ï¼Upperï¼è¿æ¯ä¸å±ï¼Lowerï¼å¯åå¨ã |
| | | /// è¿åå¼è¡¨ç¤ºè¯·æ±æ¯å¦ææï¼éé¶ä¸ºææï¼ã |
| | | /// </remarks> |
| | | /// <param name="constraint">æææºè®¾å¤å®ä¾ï¼ç¨äºè¯»å PLC å¯åå¨å¼</param> |
| | | /// <param name="layer">设å¤å±çº§ï¼å³å®è¯»å Upper è¿æ¯ Lower å¯åå¨</param> |
| | | /// <param name="isMaterial">true=读åç©æè¯·æ±æ å¿ï¼false=读ååºæè¯·æ±æ å¿</param> |
| | | /// <returns>è¯·æ±æ å¿æ¯å¦ææï¼true=æè¯·æ±ï¼false=æ 请æ±ï¼</returns> |
| | | private bool GetConstraintFlag(ConstraintMachine constraint, Layer layer, bool isMaterial) |
| | | { |
| | | // æ ¹æ® isMaterial 鿩坹åºçå¯åå¨å称对ï¼ç©æè¯·æ±æåºæè¯·æ±ï¼ |
| | | var (materialKey, outputKey) = isMaterial |
| | | ? (ConstraintMachineDBName.MaterialRequestUpper, ConstraintMachineDBName.MaterialRequestLower) // ç©æè¯·æ± |
| | | : (ConstraintMachineDBName.OutputRequestUpper, ConstraintMachineDBName.OutputRequestLower); // åºæè¯·æ± |
| | | |
| | | // æ ¹æ® layer éæ©å
·ä½ä½¿ç¨ Upper è¿æ¯ Lower çæ¬çå¯åå¨ |
| | | var key = layer == Layer.Upper ? materialKey : outputKey; |
| | | // 读åå¯åå¨å¼ï¼éé¶è¡¨ç¤ºæè¯·æ±ï¼è¿åå¸å°å¼ |
| | | return constraint.GetValue<ConstraintMachineDBName, short>(key) != 0; |
| | | } |
| | | |
| | | /// <summary> |
| | | /// è·åææéæºçè¯·æ±æ å¿ï¼ç©æè¯·æ±æåºæè¯·æ±ï¼ |
| | | /// </summary> |
| | | /// <remarks> |
| | | /// ä¸ GetConstraintFlag é»è¾ç¸åï¼ä½æä½å¯¹è±¡æ¯ææéæºï¼PinMachineï¼ã |
| | | /// æ ¹æ® isMaterial åæ°å³å®è¯»åç©æè¯·æ±è¿æ¯åºæè¯·æ±å¯åå¨ï¼ |
| | | /// åæ ¹æ® layer åæ°å³å®è¯»åä¸å±ï¼Upperï¼è¿æ¯ä¸å±ï¼Lowerï¼å¯åå¨ã |
| | | /// </remarks> |
| | | /// <param name="pinMachine">ææéæºè®¾å¤å®ä¾ï¼ç¨äºè¯»å PLC å¯åå¨å¼</param> |
| | | /// <param name="layer">设å¤å±çº§ï¼å³å®è¯»å Upper è¿æ¯ Lower å¯åå¨</param> |
| | | /// <param name="isMaterial">true=读åç©æè¯·æ±æ å¿ï¼false=读ååºæè¯·æ±æ å¿</param> |
| | | /// <returns>è¯·æ±æ å¿æ¯å¦ææï¼true=æè¯·æ±ï¼false=æ 请æ±ï¼</returns> |
| | | private bool GetPinMachineFlag(PinMachine pinMachine, Layer layer, bool isMaterial) |
| | | { |
| | | // æ ¹æ® isMaterial 鿩坹åºçå¯åå¨å称对ï¼ç©æè¯·æ±æåºæè¯·æ±ï¼ |
| | | var (materialKey, outputKey) = isMaterial |
| | | ? (PinMachineDBName.MaterialRequestUpper, PinMachineDBName.MaterialRequestLower) // ç©æè¯·æ± |
| | | : (PinMachineDBName.OutputRequestUpper, PinMachineDBName.OutputRequestLower); // åºæè¯·æ± |
| | | |
| | | // æ ¹æ® layer éæ©å
·ä½ä½¿ç¨ Upper è¿æ¯ Lower çæ¬çå¯åå¨ |
| | | var key = layer == Layer.Upper ? materialKey : outputKey; |
| | | // 读åå¯åå¨å¼ï¼éé¶è¡¨ç¤ºæè¯·æ±ï¼è¿åå¸å°å¼ |
| | | return pinMachine.GetValue<PinMachineDBName, short>(key) != 0; |
| | | } |
| | | |
| | | /// <summary> |
| | | /// è®¾ç½®æææºçè¾åºå°±ç»ªæ å¿ |
| | | /// </summary> |
| | | /// <remarks> |
| | | /// åæææºç PLC å¯åå¨åå
¥è¾åºå°±ç»ªç¶æï¼åç¥æææºå¯ä»¥ç»§ç»åºæã |
| | | /// æ ¹æ® layer åæ°å³å®åå
¥ä¸å±ï¼ConstraintTrayOutputReadyUpperï¼è¿æ¯ä¸å±ï¼ConstraintTrayOutputReadyLowerï¼å¯åå¨ã |
| | | /// </remarks> |
| | | /// <param name="constraint">æææºè®¾å¤å®ä¾ï¼ç¨äºåå
¥ PLC å¯åå¨</param> |
| | | /// <param name="layer">设å¤å±çº§ï¼å³å®åå
¥ Upper è¿æ¯ Lower å¯åå¨</param> |
| | | /// <param name="outputReady">è¾åºå°±ç»ªç¶æï¼true=å¯ä»¥åºæï¼false=ä¸è½åºæ</param> |
| | | private void SetConstraintOutputReady(ConstraintMachine constraint, Layer layer, bool outputReady) |
| | | { |
| | | // æ ¹æ® layer 鿩坹åºçè¾åºå°±ç»ªå¯åå¨ï¼Upper æ Lowerï¼ |
| | | var key = layer == Layer.Upper |
| | | ? ConstraintMachineDBName.ConstraintTrayOutputReadyUpper // ä¸å±è¾åºå°±ç»ªå¯åå¨ |
| | | : ConstraintMachineDBName.ConstraintTrayOutputReadyLower; // ä¸å±è¾åºå°±ç»ªå¯åå¨ |
| | | // å PLC åå
¥å¼ï¼outputReady 为 true æ¶åå
¥ 1ï¼å¦ååå
¥ 0 |
| | | constraint.SetValue(key, outputReady ? true : false); |
| | | } |
| | | |
| | | /// <summary> |
| | | /// 设置ææéæºçè¾åºå°±ç»ªæ å¿ |
| | | /// </summary> |
| | | /// <remarks> |
| | | /// åææéæºç PLC å¯åå¨åå
¥è¾åºå°±ç»ªç¶æï¼åç¥ææéæºå¯ä»¥ç»§ç»åºæã |
| | | /// æ ¹æ® layer åæ°å³å®åå
¥ä¸å±ï¼PlugPinTrayOutputReadyUpperï¼è¿æ¯ä¸å±ï¼PlugPinTrayOutputReadyLowerï¼å¯åå¨ã |
| | | /// </remarks> |
| | | /// <param name="pinMachine">ææéæºè®¾å¤å®ä¾ï¼ç¨äºåå
¥ PLC å¯åå¨</param> |
| | | /// <param name="layer">设å¤å±çº§ï¼å³å®åå
¥ Upper è¿æ¯ Lower å¯åå¨</param> |
| | | /// <param name="outputReady">è¾åºå°±ç»ªç¶æï¼true=å¯ä»¥åºæï¼false=ä¸è½åºæ</param> |
| | | private void SetPinMachineOutputReady(PinMachine pinMachine, Layer layer, bool outputReady) |
| | | { |
| | | // æ ¹æ® layer 鿩坹åºçè¾åºå°±ç»ªå¯åå¨ï¼Upper æ Lowerï¼ |
| | | var key = layer == Layer.Upper |
| | | ? PinMachineDBName.PlugPinTrayOutputReadyUpper // ä¸å±è¾åºå°±ç»ªå¯åå¨ |
| | | : PinMachineDBName.PlugPinTrayOutputReadyLower; // ä¸å±è¾åºå°±ç»ªå¯åå¨ |
| | | // å PLC åå
¥å¼ï¼outputReady 为 true æ¶åå
¥ 1ï¼å¦ååå
¥ 0 |
| | | pinMachine.SetValue(key, outputReady ? true : false); |
| | | } |
| | | |
| | | /// <summary> |
| | | /// å¤ç设å¤è¯·æ±çæ ¸å¿é»è¾ |
| | | /// </summary> |
| | | /// <remarks> |
| | | /// æ ¹æ®ç©æè¯·æ±ååºæè¯·æ±çç¶æï¼ |
| | | /// - 妿æç©æè¯·æ±ï¼è®¾ç½®ç®æ å°åå¹¶åé ACK |
| | | /// - 妿æåºæè¯·æ±ï¼è®¾ç½®è®¾å¤çè¾åºå°±ç»ªæ å¿ |
| | | /// æ ¹æ®ç©æè¯·æ±ååºæè¯·æ±çç¶æå³å®è¡ä¸ºï¼ |
| | | /// - å¦æè®¾å¤éè¦ç©æï¼materialRequest=trueï¼ï¼è®¾ç½®è¾é线çç®æ å°å为 1ï¼ææè¿æ¥ï¼å¹¶åå¤ ACK ç¡®è®¤ä¿¡å· |
| | | /// - å¦æè®¾å¤ä¸éè¦ç©æï¼materialRequest=falseï¼ï¼åéç¥è®¾å¤å¯ä»¥ç»§ç»åºæï¼setOutputReadyï¼ |
| | | /// |
| | | /// è¿æ¯æææºåææéæºå
±ç¨çå¤çé»è¾ï¼è®¾å¤ç¹æçé¨å已卿¤æ¹æ³å¤å°è£
ã |
| | | /// </remarks> |
| | | /// <param name="conveyorLine">è¾é线设å¤å¯¹è±¡</param> |
| | | /// <param name="childDeviceCode">å½åå设å¤ç¼ç </param> |
| | | /// <param name="getMaterialRequest">è·åç©æè¯·æ±ç¶æçå§æ</param> |
| | | /// <param name="getOutputRequest">è·ååºæè¯·æ±ç¶æçå§æ</param> |
| | | /// <param name="setOutputReady">设置è¾åºå°±ç»ªæ å¿çå§æ</param> |
| | | /// <param name="deviceType">设å¤ç±»åæè¿°</param> |
| | | /// <param name="conveyorLine">è¾é线设å¤å¯¹è±¡ï¼ç¨äºåå
¥ç®æ å°åï¼Targetï¼å ACK ä¿¡å·</param> |
| | | /// <param name="childDeviceCode">å设å¤ç¼ç ï¼ç¨äºç²¾ç¡®å®ä½åå
¥åªä¸ªå设å¤</param> |
| | | /// <param name="materialRequest">ç©æè¯·æ±æ å¿ï¼true=设å¤å½åéè¦è¡¥å
ç©æ</param> |
| | | /// <param name="outputRequest">åºæè¯·æ±æ å¿ï¼true=设å¤å½åæç©æéè¦è¾åºï¼é
å materialRequest=false æ¶ä½¿ç¨ï¼</param> |
| | | /// <param name="setOutputReady">设置设å¤è¾åºå°±ç»ªæ å¿çå§æï¼æ ¹æ®å±çº§åå
¥ Upper æ Lower å¯åå¨</param> |
| | | /// <param name="deviceType">设å¤ç±»åæè¿°å符串ï¼ç¨äºæ¥å¿è¾åº</param> |
| | | private void ProcessDeviceRequest( |
| | | CommonConveyorLine conveyorLine, |
| | | string childDeviceCode, |
| | | Func<bool> getMaterialRequest, |
| | | Func<bool> getOutputRequest, |
| | | bool materialRequest, |
| | | bool outputRequest, |
| | | Action<bool> setOutputReady, |
| | | string deviceType) |
| | | { |
| | | // è·åç©æè¯·æ±ç¶æ |
| | | bool materialReq = getMaterialRequest(); |
| | | |
| | | // è·ååºæè¯·æ±ç¶æ |
| | | bool outputReq = getOutputRequest(); |
| | | |
| | | // è®°å½å½å请æ±ç¶æçè°è¯æ¥å¿ï¼ä¾ææ¥é®é¢ä½¿ç¨ |
| | | _logger.LogDebug("ProcessDeviceRequestï¼{DeviceType}ï¼å设å¤: {ChildDeviceCode}ï¼ç©æè¯·æ±: {MaterialReq}ï¼åºæè¯·æ±: {OutputReq}", |
| | | deviceType, childDeviceCode, materialReq, outputReq); |
| | | QuartzLogger.Debug($"ProcessDeviceRequestï¼{deviceType}ï¼å设å¤: {childDeviceCode}ï¼ç©æè¯·æ±: {materialReq}ï¼åºæè¯·æ±: {outputReq}", conveyorLine.DeviceCode); |
| | | deviceType, childDeviceCode, materialRequest, outputRequest); |
| | | // 忥åå
¥ Quartz æ¥å¿æä»¶ï¼ååå¯è¿½æº¯ï¼è¿éä¿çä¸åé»è¾ä¸è´çè¡ä¸ºï¼ |
| | | QuartzLogger.Debug($"ProcessDeviceRequestï¼{deviceType}ï¼å设å¤: {childDeviceCode}ï¼ç©æè¯·æ±: {materialRequest}ï¼åºæè¯·æ±: {outputRequest}", conveyorLine.DeviceCode); |
| | | |
| | | // å¦æè®¾å¤éè¦ç©æ |
| | | if (materialReq) |
| | | // 忝夿ï¼è®¾å¤æ¯éè¦ç©æè¿æ¯éè¦åºæ |
| | | if (materialRequest) |
| | | { |
| | | // è®¾ç½®ç®æ å°å为 1ï¼è¡¨ç¤ºææè¿æ¥ï¼ |
| | | // 设å¤éè¦ç©æ -> éç¥è¾é线ææè¿æ¥ |
| | | // 1. è®¾ç½®ç®æ å°å为 1ï¼è¡¨ç¤º"ææè¿å
¥" |
| | | conveyorLine.SetValue(ConveyorLineDBNameNew.Target, 1, childDeviceCode); |
| | | |
| | | // åå¤ ACK ç¡®è®¤ä¿¡å· |
| | | // 2. åå¤ ACK 确认信å·ï¼åç¥è®¾å¤å·²æ¶å°è¯·æ± |
| | | conveyorLine.SetValue(ConveyorLineDBNameNew.WCS_ACK, 1, childDeviceCode); |
| | | |
| | | // 3. è®°å½ä¿¡æ¯æ¥å¿ï¼è¡¨æå·²å®æç®æ å°å设置å ACK åå¤ |
| | | _logger.LogInformation("ProcessDeviceRequestï¼{DeviceType} éè¦ç©æï¼å·²è®¾ç½®ç®æ å°ååACK", deviceType); |
| | | QuartzLogger.Info($"ProcessDeviceRequestï¼{deviceType} éè¦ç©æï¼å·²è®¾ç½®ç®æ å°ååACK", conveyorLine.DeviceCode); |
| | | } |
| | | else |
| | | { |
| | | // 设å¤ä¸éè¦ç©æï¼è®¾ç½®è¾åºå°±ç»ªæ å¿ |
| | | // éç¥è®¾å¤å¯ä»¥ç»§ç»åºæ |
| | | setOutputReady(outputReq); |
| | | // 设å¤ä¸éè¦ç©æ -> éç¥è®¾å¤å¯ä»¥ç»§ç»åºæï¼æ 论å½åæ¯å¦æè´§è¦åºï¼é½è¦éç¥ï¼ |
| | | // outputRequest 表示设å¤å½åæ¯å¦ç¡®å®æè´§ï¼å¦ææ²¡æè´§å outputReady=falseï¼è®¾å¤æ¶å°åçå¾
|
| | | setOutputReady(outputRequest); |
| | | } |
| | | } |
| | | |
| | | /// <summary> |
| | | /// åå
¥è°è¯æ¥å¿ï¼åæ¶è¾åºå°ä¸¤ä¸ªæ¥å¿ç³»ç»ï¼ |
| | | /// </summary> |
| | | /// <remarks> |
| | | /// ç»ä¸å
¥å£ç¹æ¥å¿æ ¼å¼ï¼åæ¶å Microsoft.Extensions.Logging å QuartzLogger åå
¥ï¼ |
| | | /// ä¿è¯æ¥å¿æ¢è½å¨æ§å¶å°æ¥çä¹è½å¨æä»¶ä¸è¿½æº¯ã |
| | | /// </remarks> |
| | | /// <param name="conveyorLine">è¾é线设å¤å¯¹è±¡ï¼ç¨äºè·å设å¤ç¼ç åå
¥ QuartzLogger</param> |
| | | /// <param name="scenario">åºæ¯æè¿°ï¼å¦"å
¥åºä¸ä¸å°å"æ"åºåºä¸ä¸å°å"</param> |
| | | /// <param name="childDeviceCode">å设å¤ç¼ç </param> |
| | | /// <param name="nextAddress">ç®æ 设å¤ç¼ç </param> |
| | | private void WriteDebug(CommonConveyorLine conveyorLine, string scenario, string childDeviceCode, string nextAddress) |
| | | { |
| | | // åå
¥ç»æåæ¥å¿ï¼å¯è¢« Serilog çæ¥å¿æ¡æ¶æè·ï¼ |
| | | _logger.LogDebug("Handle{Scenario}ï¼å设å¤: {ChildDeviceCode}ï¼ç®æ å°å: {NextAddress}", |
| | | scenario, childDeviceCode, nextAddress); |
| | | // åå
¥ Quartz ä¸ç¨æ¥å¿æä»¶ï¼ä¾å®æ¶ä»»å¡è½¨è¿¹è¿½è¸ªï¼ |
| | | QuartzLogger.Debug($"Handle{scenario}ï¼å设å¤: {childDeviceCode}ï¼ç®æ å°å: {nextAddress}", conveyorLine.DeviceCode); |
| | | } |
| | | } |
| | | } |
| | |
| | | } |
| | | |
| | | // æ£æ¥ä»»å¡æ»æ°æ¯å¦æªè¾¾å°ä¸é |
| | | if (latestState.RobotTaskTotalNum < MaxTaskTotalNum) |
| | | { |
| | | //if (latestState.RobotTaskTotalNum < MaxTaskTotalNum) |
| | | //{ |
| | | // è°ç¨å·¥ä½æµç¼æå¨æ§è¡ä»»å¡ |
| | | // ç¼æå¨ä¼æ ¹æ®å½åç¶æå³å®ä¸ä¸æ¥å¨ä½ |
| | | await _workflowOrchestrator.ExecuteAsync(latestState, task, ipAddress); |
| | | } |
| | | //} |
| | | } |
| | | } |
| | | catch (Exception ex) |
| | |
| | | state.OperStatus = "Homed"; |
| | | return true; |
| | | |
| | | // æºå¨äººæ£å¨è¿è¡ |
| | | case "running": |
| | | state.OperStatus = "Running"; |
| | | return true; |
| | | |
| | | // æºå¨äººæ£å¨æå |
| | | case "pausing": |
| | | state.OperStatus = "Pausing"; |
| | | return true; |
| | | |
| | | // æºå¨äººæ£å¨é¢ç |
| | | case "warming": |
| | | state.OperStatus = "Warming"; |
| | | return true; |
| | | |
| | | // æºå¨äººæ£å¨æ¥å |
| | | case "emstoping": |
| | | state.OperStatus = "Emstoping"; |
| | | return true; |
| | | |
| | | // æºå¨äººæ£å¨åè´§ |
| | | case "picking": |
| | | state.CurrentAction = "Picking"; |
| | |
| | | } |
| | | return false; |
| | | } |
| | | |
| | | // ==================== è¿è¡ç¶æå½ä»¤ï¼ç»ï¼ ==================== |
| | | |
| | | // æºå¨äººæ£å¨è¿è¡ |
| | | case "running": |
| | | state.OperStatus = "Running"; |
| | | return true; |
| | | |
| | | // æºå¨äººæ£å¨æå |
| | | case "pausing": |
| | | state.OperStatus = "Pausing"; |
| | | return true; |
| | | |
| | | // æºå¨äººæ£å¨é¢ç |
| | | case "warming": |
| | | state.OperStatus = "Warming"; |
| | | return true; |
| | | |
| | | // æºå¨äººæ£å¨æ¥å |
| | | case "emstoping": |
| | | state.OperStatus = "Emstoping"; |
| | | return true; |
| | | |
| | | // ==================== 模å¼åæ¢å½ä»¤ ==================== |
| | | |
| | |
| | | using Microsoft.Extensions.Logging; |
| | | using WIDESEA_Core; |
| | | using WIDESEAWCS_Common.TaskEnum; |
| | | using WIDESEAWCS_Core.Helper; |
| | | using WIDESEAWCS_Core.LogHelper; |
| | | using WIDESEAWCS_ITaskInfoService; |
| | | using WIDESEAWCS_Model.Models; |
| | |
| | | // æ£æ¥æ¯å¦æ»¡è¶³èªå¨æ§å¶æ¡ä»¶ï¼ |
| | | // 1. è¿è¡æ¨¡å¼ä¸ºèªå¨ï¼2ï¼ |
| | | // 2. æ§å¶æ¨¡å¼ä¸ºå®¢æ·ç«¯æ§å¶ï¼1ï¼ |
| | | // 3. è¿è¡ç¶æä¸æ¯ Runningï¼è¯´æå·²å®æå½åå¨ä½ï¼ |
| | | if (latestState.RobotRunMode == 2 && latestState.RobotControlMode == 1 && latestState.OperStatus != "Running") |
| | | // 3. è¿è¡ç¶ææ¯ Running |
| | | if (latestState.RobotRunMode == 2 /*&& latestState.RobotControlMode == 1*/ && latestState.OperStatus == "Running") |
| | | { |
| | | if(latestState.CurrentAction == "Picking" || latestState.CurrentAction == "Puting") |
| | | { |
| | | return; |
| | | } |
| | | |
| | | // ========== åè´§å®æåçæ¾è´§å¤ç ========== |
| | | // æ¡ä»¶ï¼ |
| | | // - å½åå¨ä½æ¯ PickFinished æ AllPickFinishedï¼åè´§å®æï¼ |
| | | // - æèä¸æç©æï¼RobotArmObject == 1ï¼ |
| | | // - ä»»å¡ç¶æä¸º RobotPickFinishï¼å·²è®°å½åè´§å®æï¼ |
| | | if ((latestState.CurrentAction == "PickFinished" || latestState.CurrentAction == "AllPickFinished") |
| | | && latestState.RobotArmObject == 1 |
| | | && latestState.RobotArmObject == 0 |
| | | && task.RobotTaskState == TaskRobotStatusEnum.RobotPickFinish.GetHashCode()) |
| | | { |
| | | _logger.LogInformation("ExecuteAsyncï¼æ»¡è¶³æ¾è´§æ¡ä»¶ï¼å¼å§å¤çåè´§å®æï¼ä»»å¡å·: {TaskNum}", task.RobotTaskNum); |
| | |
| | | // åéæ¾è´§æä»¤ |
| | | await HandlePickFinishedStateAsync(task, ipAddress); |
| | | } |
| | | // ========== æ¾è´§å®æåçåè´§å¤ç ========== |
| | | |
| | | // ========== åå§åæè
æ¾è´§å®æåçåè´§å¤ç ========== |
| | | // æ¡ä»¶ï¼ |
| | | // - å½åå¨ä½æ¯ PutFinishedãAllPutFinished æ nullï¼æ¾è´§å®æï¼ |
| | | // - è¿è¡ç¶æä¸º Homedï¼å·²å½ä½ï¼ |
| | | // - æè䏿 ç©æï¼RobotArmObject == 0ï¼ |
| | | // - ä»»å¡ç¶æä¸º RobotPutFinish æä¸æ¯ RobotExecuting |
| | | else if ((latestState.CurrentAction == "PutFinished" || latestState.CurrentAction == "AllPutFinished" || latestState.CurrentAction == null) |
| | | && latestState.OperStatus == "Homed" |
| | | else if ((latestState.CurrentAction == "PutFinished" || latestState.CurrentAction == "AllPutFinished" || latestState.CurrentAction.IsNullOrEmpty()) |
| | | && latestState.RobotArmObject == 0 |
| | | && (task.RobotTaskState == TaskRobotStatusEnum.RobotPutFinish.GetHashCode() |
| | | || task.RobotTaskState != TaskRobotStatusEnum.RobotExecuting.GetHashCode())) |
| | |
| | | <vol-table |
| | | ref="table" |
| | | :single="single" |
| | | :expand="tableExpand" |
| | | :rowKey="rowKey" |
| | | :loadTreeChildren="loadTreeTableChildren" |
| | | @loadBefore="loadTableBefore" |
| | |
| | | let props = { |
| | | columns: {//å½å表çé
ç½®ä¿¡æ¯ |
| | | columns: { |
| | | type: Array, |
| | | default: () => { |
| | | return []; |
| | | } |
| | | }, |
| | | detail: {//ä»è¡¨æç»é
ç½® |
| | | detail: { |
| | | type: Object, |
| | | default: () => { |
| | | return { |
| | | columns: [],//ä»è¡¨å |
| | | sortName: ""//ä»è¡¨æåºå段 |
| | | columns: [], |
| | | sortName: "" |
| | | }; |
| | | } |
| | | }, |
| | | editFormFields: {//æ°å»ºãç¼è¾å段(key/value) |
| | | editFormFields: { |
| | | type: Object, |
| | | default: () => { |
| | | return {}; |
| | | } |
| | | }, |
| | | editFormOptions: {//æ°å»ºãç¼è¾é
ç½®ä¿¡æ¯ |
| | | editFormOptions: { |
| | | type: Array, |
| | | default: () => { |
| | | return []; |
| | | } |
| | | }, |
| | | searchFormFields: {//æ¥è¯¢å段(key/value) |
| | | searchFormFields: { |
| | | type: Object, |
| | | default: () => { |
| | | return {}; |
| | | } |
| | | }, |
| | | searchFormOptions: {//æ¥è¯¢é
置信æ¯(key/value) |
| | | searchFormOptions: { |
| | | type: Array, |
| | | default: () => { |
| | | return []; |
| | | } |
| | | }, |
| | | table: {//表çé
置信æ¯ï¼ä¸»é®ãæåºç |
| | | table: { |
| | | type: Object, |
| | | default: () => { |
| | | return {}; |
| | | } |
| | | }, |
| | | extend: {//è¡¨çæ©å±æ¹æ³ä¸ç»ä»¶é½åå¹¶å°æ¤å±æ§ä¸ |
| | | tableExpand: { |
| | | type: Object, |
| | | default: () => { |
| | | return {}; |
| | | } |
| | | }, |
| | | extend: { |
| | | type: Object, |
| | | default: () => { |
| | | return {}; |
| | | } |
| | | } |
| | | } |
| | | }; |
| | | |
| | | export default props; |
| | | export default props; |
| | |
| | | @select="userSelect" |
| | | @select-all="userSelect" |
| | | @selection-change="selectionChange" |
| | | @expand-change="expandChange" |
| | | @row-dblclick="rowDbClick" |
| | | @row-click="rowClick" |
| | | @header-click="headerClick" |
| | |
| | | style="width: 100%" |
| | | :scrollbar-always-on="true" |
| | | > |
| | | <el-table-column |
| | | v-if="showExpand" |
| | | type="expand" |
| | | :fixed="expand.fixed" |
| | | :width="expand.width || 55" |
| | | > |
| | | <template #default="scope"> |
| | | <div class="expand-cell"> |
| | | <table-render |
| | | v-if="expand.render && typeof expand.render == 'function'" |
| | | :row="scope.row" |
| | | :index="scope.$index" |
| | | :column="expand" |
| | | :render="expand.render" |
| | | ></table-render> |
| | | </div> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column |
| | | v-if="ck" |
| | | type="selection" |
| | |
| | | return 1; |
| | | }, |
| | | }, |
| | | expand: { |
| | | type: Object, |
| | | default: () => { |
| | | return {}; |
| | | }, |
| | | }, |
| | | pagination: { |
| | | type: Object, |
| | | default: function () { |
| | |
| | | this.defaultLoadPage && this.load(); |
| | | }, |
| | | computed: { |
| | | showExpand() { |
| | | return !!(this.expand && typeof this.expand.render === "function"); |
| | | }, |
| | | filterColumns() { |
| | | return this.columns.filter((x, index) => { |
| | | if (!x.field) { |
| | |
| | | }, |
| | | }, |
| | | methods: { |
| | | expandChange(row, expandedRows) { |
| | | if (this.expand && typeof this.expand.onChange === "function") { |
| | | this.expand.onChange(row, expandedRows, this); |
| | | } |
| | | this.$emit("expandChange", { row, expandedRows }); |
| | | }, |
| | | watchRowSelectChange(newLen, oldLen) { |
| | | if (newLen < oldLen && this.selectRows.length) { |
| | | this.selectRows = []; |
| | |
| | | border-bottom: 1px solid; |
| | | padding-bottom: 2px; |
| | | } |
| | | .vol-table .expand-cell { |
| | | padding: 8px 0; |
| | | } |
| | | .vol-table .empty-tag { |
| | | border: none; |
| | | background: none; |
| | |
| | | |
| | | <template> |
| | | <view-grid |
| | | ref="grid" |
| | | :columns="columns" |
| | | :detail="detail" |
| | | :editFormFields="editFormFields" |
| | | :editFormOptions="editFormOptions" |
| | | :searchFormFields="searchFormFields" |
| | | :searchFormOptions="searchFormOptions" |
| | | :table="table" |
| | | :extend="extend" |
| | | > |
| | | </view-grid> |
| | | </template> |
| | | <script> |
| | | import extend from "@/extension/stock/stockInfo.js"; |
| | | import { ref, defineComponent } from "vue"; |
| | | export default defineComponent({ |
| | | setup() { |
| | | const table = ref({ |
| | | key: "id", |
| | | footer: "Foots", |
| | | cnName: "åºåä¿¡æ¯", |
| | | name: "stockInfo", |
| | | url: "/StockInfo/", |
| | | sortName: "id", |
| | | }); |
| | | const editFormFields = ref({ |
| | | deviceCode: "", |
| | | deviceName: "", |
| | | deviceType: "", |
| | | deviceStatus: "", |
| | | deviceIp: "", |
| | | devicePort: "", |
| | | devicePlcType: "", |
| | | deviceRemark: "", |
| | | }); |
| | | const editFormOptions = ref([ |
| | | [ |
| | | {field:'palletCode',title:'æçç¼å·',type:'string'}, |
| | | {field:'locationCode',title:'è´§ä½ç¼å·',type:'string'}, |
| | | ] |
| | | <view-grid |
| | | ref="grid" |
| | | :columns="columns" |
| | | :detail="detail" |
| | | :editFormFields="editFormFields" |
| | | :editFormOptions="editFormOptions" |
| | | :searchFormFields="searchFormFields" |
| | | :searchFormOptions="searchFormOptions" |
| | | :table="table" |
| | | :tableExpand="tableExpand" |
| | | :extend="extend" |
| | | > |
| | | </view-grid> |
| | | </template> |
| | | |
| | | <script> |
| | | import extend from "@/extension/stock/stockInfo.js"; |
| | | import { |
| | | defineComponent, |
| | | getCurrentInstance, |
| | | h, |
| | | reactive, |
| | | ref, |
| | | resolveComponent, |
| | | } from "vue"; |
| | | |
| | | const TEXT = { |
| | | pageName: "åºåä¿¡æ¯", |
| | | palletCode: "æçç¼å·", |
| | | locationCode: "è´§ä½ç¼å·", |
| | | warehouse: "ä»åº", |
| | | creator: "å建人", |
| | | createDate: "å建æ¶é´", |
| | | modifier: "ä¿®æ¹äºº", |
| | | modifyDate: "ä¿®æ¹æ¶é´", |
| | | detailName: "åºåæç»", |
| | | materielName: "ç©æåç§°", |
| | | serialNumber: "çµè¯ç ", |
| | | stockQuantity: "åºåæ°é", |
| | | status: "ç¶æ", |
| | | inboundOrderRowNo: "ééå·", |
| | | detailLoading: "åºåæç»å è½½ä¸...", |
| | | detailLoadFailed: "åºåæç»å 载失败", |
| | | detailEmpty: "å½ååºåå¤´ææ æç»æ°æ®", |
| | | expandPrefix: "æçï¼", |
| | | expandMiddle: " / ", |
| | | expandLocation: "è´§ä½ï¼", |
| | | }; |
| | | |
| | | export default defineComponent({ |
| | | setup() { |
| | | const { proxy } = getCurrentInstance(); |
| | | const ElTable = resolveComponent("el-table"); |
| | | const ElTableColumn = resolveComponent("el-table-column"); |
| | | |
| | | const table = ref({ |
| | | key: "id", |
| | | footer: "Foots", |
| | | cnName: TEXT.pageName, |
| | | name: "stockInfo", |
| | | url: "/StockInfo/", |
| | | sortName: "id", |
| | | }); |
| | | |
| | | const editFormFields = ref({ |
| | | palletCode: "", |
| | | locationCode: "", |
| | | }); |
| | | |
| | | const editFormOptions = ref([ |
| | | [ |
| | | { field: "palletCode", title: TEXT.palletCode, type: "string" }, |
| | | { field: "locationCode", title: TEXT.locationCode, type: "string" }, |
| | | ], |
| | | ]); |
| | | |
| | | const searchFormFields = ref({ |
| | | palletCode: "", |
| | | locationCode: "", |
| | | }); |
| | | |
| | | const searchFormOptions = ref([ |
| | | [ |
| | | { title: TEXT.palletCode, field: "palletCode", type: "like" }, |
| | | { title: TEXT.locationCode, field: "locationCode", type: "like" }, |
| | | ], |
| | | ]); |
| | | |
| | | const columns = ref([ |
| | | { |
| | | field: "id", |
| | | title: "Id", |
| | | type: "int", |
| | | width: 90, |
| | | hidden: true, |
| | | readonly: true, |
| | | require: true, |
| | | align: "left", |
| | | }, |
| | | { |
| | | field: "palletCode", |
| | | title: TEXT.palletCode, |
| | | type: "string", |
| | | width: 120, |
| | | align: "left", |
| | | }, |
| | | { |
| | | field: "locationCode", |
| | | title: TEXT.locationCode, |
| | | type: "string", |
| | | width: 150, |
| | | align: "left", |
| | | }, |
| | | { |
| | | field: "warehouseId", |
| | | title: TEXT.warehouse, |
| | | type: "select", |
| | | width: 100, |
| | | align: "left", |
| | | bind: { key: "warehouseEnum", data: [] }, |
| | | }, |
| | | { |
| | | field: "creater", |
| | | title: TEXT.creator, |
| | | type: "string", |
| | | width: 90, |
| | | align: "left", |
| | | }, |
| | | { |
| | | field: "createDate", |
| | | title: TEXT.createDate, |
| | | type: "datetime", |
| | | width: 160, |
| | | align: "left", |
| | | }, |
| | | { |
| | | field: "modifier", |
| | | title: TEXT.modifier, |
| | | type: "string", |
| | | width: 100, |
| | | align: "left", |
| | | hidden: true, |
| | | }, |
| | | { |
| | | field: "modifyDate", |
| | | title: TEXT.modifyDate, |
| | | type: "datetime", |
| | | width: 160, |
| | | align: "left", |
| | | hidden: true, |
| | | }, |
| | | ]); |
| | | |
| | | const detail = ref({ |
| | | cnName: "#detailCnName", |
| | | table: "", |
| | | columns: [], |
| | | sortName: "", |
| | | }); |
| | | |
| | | const detailState = reactive({ |
| | | rowsMap: {}, |
| | | loadingMap: {}, |
| | | errorMap: {}, |
| | | }); |
| | | |
| | | const stockStatusOptions = ref([]); |
| | | |
| | | const detailColumns = [ |
| | | { field: "materielName", title: TEXT.materielName, minWidth: 160 }, |
| | | { field: "serialNumber", title: TEXT.serialNumber, minWidth: 160 }, |
| | | { field: "stockQuantity", title: TEXT.stockQuantity, minWidth: 120 }, |
| | | { field: "status", title: TEXT.status, minWidth: 120 }, |
| | | { field: "inboundOrderRowNo", title: TEXT.inboundOrderRowNo, minWidth: 120 }, |
| | | ]; |
| | | |
| | | const normalizeValue = (value) => { |
| | | return value === null || value === undefined || value === "" ? "--" : value; |
| | | }; |
| | | |
| | | const formatStatusText = (value) => { |
| | | const matched = stockStatusOptions.value.find((item) => `${item.key}` === `${value}`); |
| | | return matched ? matched.value || matched.label : normalizeValue(value); |
| | | }; |
| | | |
| | | const getDetailRows = (stockId) => { |
| | | return detailState.rowsMap[stockId] || []; |
| | | }; |
| | | |
| | | const loadDetailRows = async (row) => { |
| | | if (!row || !row.id || detailState.loadingMap[row.id]) { |
| | | return; |
| | | } |
| | | if (detailState.rowsMap[row.id]) { |
| | | return; |
| | | } |
| | | |
| | | detailState.loadingMap[row.id] = true; |
| | | detailState.errorMap[row.id] = ""; |
| | | try { |
| | | const result = await proxy.http.post("/api/StockInfoDetail/getPageData", { |
| | | page: 1, |
| | | rows: 200, |
| | | sort: "id", |
| | | order: "asc", |
| | | wheres: JSON.stringify([ |
| | | { |
| | | name: "stockId", |
| | | value: String(row.id), |
| | | displayType: "int", |
| | | }, |
| | | ]), |
| | | }); |
| | | detailState.rowsMap[row.id] = (result && result.rows) || []; |
| | | } catch (error) { |
| | | detailState.rowsMap[row.id] = null; |
| | | detailState.errorMap[row.id] = error?.message || TEXT.detailLoadFailed; |
| | | } finally { |
| | | detailState.loadingMap[row.id] = false; |
| | | } |
| | | }; |
| | | |
| | | const loadStockStatusOptions = async () => { |
| | | try { |
| | | const result = await proxy.http.post("/api/Sys_Dictionary/GetVueDictionary", ["stockStatusEmun"]); |
| | | const matched = (result || []).find((item) => item.dicNo === "stockStatusEmun"); |
| | | stockStatusOptions.value = matched ? matched.data || [] : []; |
| | | } catch (error) { |
| | | stockStatusOptions.value = []; |
| | | } |
| | | }; |
| | | |
| | | loadStockStatusOptions(); |
| | | |
| | | const renderStatus = (row) => { |
| | | if (detailState.loadingMap[row.id]) { |
| | | return h("div", { class: "stock-detail-status" }, TEXT.detailLoading); |
| | | } |
| | | if (detailState.errorMap[row.id]) { |
| | | return h( |
| | | "div", |
| | | { class: "stock-detail-status stock-detail-status--error" }, |
| | | detailState.errorMap[row.id] |
| | | ); |
| | | } |
| | | return null; |
| | | }; |
| | | |
| | | const renderDetailTable = (row) => { |
| | | const statusNode = renderStatus(row); |
| | | if (statusNode) { |
| | | return statusNode; |
| | | } |
| | | |
| | | const rows = getDetailRows(row.id); |
| | | if (!rows.length) { |
| | | return h("div", { class: "stock-detail-status" }, TEXT.detailEmpty); |
| | | } |
| | | |
| | | return h("div", { class: "stock-detail-table-wrapper" }, [ |
| | | h("div", { class: "stock-detail-toolbar" }, [ |
| | | h("div", { class: "stock-detail-toolbar__left" }, TEXT.detailName), |
| | | h("div", { class: "stock-detail-toolbar__right" }, [ |
| | | h("span", { class: "stock-detail-count" }, `${rows.length} æ¡`), |
| | | ]), |
| | | ]), |
| | | h( |
| | | ElTable, |
| | | { |
| | | data: rows, |
| | | border: true, |
| | | stripe: true, |
| | | size: "small", |
| | | class: "stock-detail-el-table", |
| | | maxHeight: 420, |
| | | emptyText: TEXT.detailEmpty, |
| | | }, |
| | | () => |
| | | detailColumns.map((column) => |
| | | h(ElTableColumn, { |
| | | key: column.field, |
| | | prop: column.field, |
| | | label: column.title, |
| | | minWidth: column.minWidth, |
| | | showOverflowTooltip: true, |
| | | formatter: (detailRow) => |
| | | column.field === "status" |
| | | ? formatStatusText(detailRow[column.field]) |
| | | : normalizeValue(detailRow[column.field]), |
| | | }) |
| | | ) |
| | | ), |
| | | ]); |
| | | const searchFormFields = ref({ |
| | | palletCode: "", |
| | | locationCode: "", |
| | | }); |
| | | const searchFormOptions = ref([ |
| | | [ |
| | | { title: "æçç¼å·", field: "palletCode" }, |
| | | { title: "è´§ä½ç¼å·", field: "locationCode" }, |
| | | ], |
| | | ]); |
| | | const columns = ref([ |
| | | { |
| | | field: "id", |
| | | title: "Id", |
| | | type: "int", |
| | | width: 90, |
| | | hidden: true, |
| | | readonly: true, |
| | | require: true, |
| | | align: "left", |
| | | }, |
| | | { |
| | | field: "palletCode", |
| | | title: "æçç¼å·", |
| | | type: "string", |
| | | width: 90, |
| | | align: "left", |
| | | }, |
| | | { |
| | | field: "locationCode", |
| | | title: "è´§ä½ç¼å·", |
| | | type: "string", |
| | | width: 150, |
| | | align: "left", |
| | | }, |
| | | // { |
| | | // field: "isFull", |
| | | // title: "æ¯å¦æ»¡ç", |
| | | // type: "string", |
| | | // width: 150, |
| | | // align: "left", |
| | | // bind: { key: "yesno", data: [] }, |
| | | // }, |
| | | { |
| | | field: "warehouseId", |
| | | title: "ä»åº", |
| | | type: "select", |
| | | width: 100, |
| | | align: "left", |
| | | bind: { key: "warehouseEnum", data: [] }, |
| | | }, |
| | | { |
| | | field: "creater", |
| | | title: "å建人", |
| | | type: "string", |
| | | width: 90, |
| | | align: "left", |
| | | }, |
| | | { |
| | | field: "createDate", |
| | | title: "å建æ¶é´", |
| | | type: "datetime", |
| | | width: 160, |
| | | align: "left", |
| | | }, |
| | | { |
| | | field: "modifier", |
| | | title: "ä¿®æ¹äºº", |
| | | type: "string", |
| | | width: 100, |
| | | align: "left", |
| | | hidden:true |
| | | }, |
| | | { |
| | | field: "modifyDate", |
| | | title: "ä¿®æ¹æ¶é´", |
| | | type: "datetime", |
| | | width: 160, |
| | | align: "left", |
| | | hidden:true |
| | | }, |
| | | { |
| | | field: "remark", |
| | | title: "夿³¨", |
| | | type: "string", |
| | | width: 100, |
| | | align: "left", |
| | | hidden:true |
| | | }, |
| | | ]); |
| | | const detail = ref({ |
| | | cnName: "#detailCnName", |
| | | table: "", |
| | | columns: [], |
| | | sortName: "", |
| | | }); |
| | | return { |
| | | table, |
| | | extend, |
| | | editFormFields, |
| | | editFormOptions, |
| | | searchFormFields, |
| | | searchFormOptions, |
| | | columns, |
| | | detail, |
| | | }; |
| | | }, |
| | | }); |
| | | </script> |
| | | |
| | | }; |
| | | |
| | | const tableExpand = ref({ |
| | | width: 55, |
| | | onChange(row, expandedRows) { |
| | | const isExpanded = expandedRows.some((item) => item.id === row.id); |
| | | if (isExpanded) { |
| | | loadDetailRows(row); |
| | | } |
| | | }, |
| | | render(render, { row }) { |
| | | return render("div", { class: "stock-detail-panel" }, [ |
| | | render("div", { class: "stock-detail-header" }, [ |
| | | render("div", { class: "stock-detail-header__main" }, [ |
| | | render("div", { class: "stock-detail-title" }, TEXT.detailName), |
| | | render( |
| | | "div", |
| | | { class: "stock-detail-subtitle" }, |
| | | `${TEXT.expandPrefix}${normalizeValue(row.palletCode)}${TEXT.expandMiddle}${TEXT.expandLocation}${normalizeValue(row.locationCode)}` |
| | | ), |
| | | ]), |
| | | // render("div", { class: "stock-detail-tags" }, [ |
| | | // render("span", { class: "stock-detail-tag" }, normalizeValue(row.palletCode)), |
| | | // render( |
| | | // "span", |
| | | // { class: "stock-detail-tag stock-detail-tag--muted" }, |
| | | // normalizeValue(row.locationCode) |
| | | // ), |
| | | // ]), |
| | | ]), |
| | | renderDetailTable(row), |
| | | ]); |
| | | }, |
| | | }); |
| | | |
| | | return { |
| | | table, |
| | | extend, |
| | | editFormFields, |
| | | editFormOptions, |
| | | searchFormFields, |
| | | searchFormOptions, |
| | | columns, |
| | | detail, |
| | | tableExpand, |
| | | }; |
| | | }, |
| | | }); |
| | | </script> |
| | | |
| | | <style scoped> |
| | | .stock-detail-panel { |
| | | margin: 4px 8px 12px; |
| | | padding: 14px 16px 16px; |
| | | background: linear-gradient(180deg, #ffffff 0%, #fafbfc 100%); |
| | | border: 1px solid #e8edf3; |
| | | border-radius: 10px; |
| | | box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.7); |
| | | } |
| | | |
| | | .stock-detail-header { |
| | | display: flex; |
| | | align-items: flex-start; |
| | | justify-content: space-between; |
| | | gap: 12px; |
| | | margin-bottom: 12px; |
| | | padding-bottom: 12px; |
| | | border-bottom: 1px solid #edf1f5; |
| | | } |
| | | |
| | | .stock-detail-header__main { |
| | | min-width: 0; |
| | | } |
| | | |
| | | .stock-detail-title { |
| | | margin-bottom: 4px; |
| | | font-size: 15px; |
| | | font-weight: 700; |
| | | color: #303133; |
| | | } |
| | | |
| | | .stock-detail-subtitle { |
| | | font-size: 13px; |
| | | color: #606266; |
| | | line-height: 1.6; |
| | | } |
| | | |
| | | .stock-detail-tags { |
| | | display: flex; |
| | | flex-wrap: wrap; |
| | | justify-content: flex-end; |
| | | gap: 8px; |
| | | } |
| | | |
| | | .stock-detail-tag { |
| | | display: inline-flex; |
| | | align-items: center; |
| | | height: 28px; |
| | | padding: 0 10px; |
| | | color: #1f5eff; |
| | | background: #edf4ff; |
| | | border: 1px solid #d8e6ff; |
| | | border-radius: 999px; |
| | | font-size: 12px; |
| | | font-weight: 600; |
| | | } |
| | | |
| | | .stock-detail-tag--muted { |
| | | color: #4e5969; |
| | | background: #f4f6f8; |
| | | border-color: #e5e9ef; |
| | | } |
| | | |
| | | .stock-detail-status { |
| | | padding: 14px 12px; |
| | | color: #606266; |
| | | background: #f8fafc; |
| | | border: 1px dashed #d9e2ec; |
| | | border-radius: 8px; |
| | | } |
| | | |
| | | .stock-detail-status--error { |
| | | color: #f56c6c; |
| | | background: #fef0f0; |
| | | border-color: #fde2e2; |
| | | } |
| | | |
| | | .stock-detail-table-wrapper { |
| | | overflow-x: auto; |
| | | border: 1px solid #ebeef5; |
| | | border-radius: 8px; |
| | | background: #fff; |
| | | } |
| | | |
| | | .stock-detail-toolbar { |
| | | display: flex; |
| | | align-items: center; |
| | | justify-content: space-between; |
| | | gap: 12px; |
| | | padding: 12px 14px; |
| | | background: #f8fafc; |
| | | border-bottom: 1px solid #edf1f5; |
| | | } |
| | | |
| | | .stock-detail-toolbar__left { |
| | | font-size: 13px; |
| | | font-weight: 600; |
| | | color: #303133; |
| | | } |
| | | |
| | | .stock-detail-count { |
| | | display: inline-flex; |
| | | align-items: center; |
| | | height: 24px; |
| | | padding: 0 10px; |
| | | color: #606266; |
| | | background: #fff; |
| | | border: 1px solid #e5e9ef; |
| | | border-radius: 999px; |
| | | font-size: 12px; |
| | | } |
| | | |
| | | :deep(.stock-detail-el-table) { |
| | | border-top: none; |
| | | } |
| | | |
| | | :deep(.stock-detail-el-table .el-table__inner-wrapper::before) { |
| | | display: none; |
| | | } |
| | | |
| | | :deep(.stock-detail-el-table th.el-table__cell) { |
| | | background: #f5f7fa; |
| | | color: #303133; |
| | | font-weight: 600; |
| | | } |
| | | |
| | | :deep(.stock-detail-el-table td.el-table__cell) { |
| | | color: #606266; |
| | | } |
| | | |
| | | :deep(.stock-detail-el-table .el-table__body tr:hover > td.el-table__cell) { |
| | | background: #f0f7ff; |
| | | } |
| | | </style> |
| | |
| | | field: "beginDate", |
| | | title: "å¼å§æ¶é´", |
| | | type: "datetime", |
| | | width: 140, |
| | | width: 70, |
| | | align: "left", |
| | | sortable: true, |
| | | }, |
| | |
| | | field: "elapsedTime", |
| | | title: "æ¶é¿", |
| | | type: "int", |
| | | width: 60, |
| | | width: 40, |
| | | align: "left", |
| | | }, |
| | | { |
| | |
| | | field: "requestParam", |
| | | title: "请æ±åæ°", |
| | | type: "string", |
| | | width: 70, |
| | | width: 100, |
| | | align: "left", |
| | | }, |
| | | { |
| | | field: "responseParam", |
| | | title: "ååºåæ°", |
| | | type: "string", |
| | | width: 70, |
| | | width: 100, |
| | | align: "left", |
| | | }, |
| | | { |
| | |
| | | }; |
| | | }, |
| | | }); |
| | | </script> |
| | | |
| | | </script> |
| | |
| | | type: "int", |
| | | width: 120, |
| | | align: "left", |
| | | bind: { key: "taskType", data: [] }, |
| | | bind: { key: "taskTypeEnum", data: [] }, |
| | | }, |
| | | { |
| | | field: "taskStatus", |
| | |
| | | private readonly IRepository<Dt_Task> _taskRepository; |
| | | private readonly IRepository<Dt_StockInfo> _stockInfoRepository; |
| | | private readonly IRecordService _recordService; |
| | | private readonly IRepository<Dt_Warehouse> _warehouseRepository; |
| | | |
| | | /// <summary> |
| | | /// æé 彿° |
| | |
| | | IRepository<Dt_LocationInfo> baseDal, |
| | | IRepository<Dt_Task> taskRepository, |
| | | IRepository<Dt_StockInfo> stockInfoRepository, |
| | | IRepository<Dt_Warehouse> warehouseRepository, |
| | | IMapper mapper, |
| | | IRecordService recordService) : base(baseDal) |
| | | { |
| | |
| | | _stockInfoRepository = stockInfoRepository; |
| | | _mapper = mapper; |
| | | _recordService = recordService; |
| | | _warehouseRepository = warehouseRepository; |
| | | } |
| | | |
| | | /// <summary> |
| | |
| | | x.LocationStatus == LocationStatusEnum.Free.GetHashCode()); |
| | | |
| | | return locations? |
| | | .OrderBy(x => x.Layer) |
| | | .ThenByDescending(x => x.Depth) |
| | | .ThenBy(x => x.Column) |
| | | .ThenBy(x => x.Row) |
| | | .OrderByDescending(x => x.Depth) // 1. 深度ä¼å
ï¼ä»å¤§å°å°ï¼ |
| | | .ThenBy(x => x.Layer) // 2. 屿° |
| | | .ThenBy(x => x.Column) // 3. å |
| | | .ThenBy(x => x.Row) // 4. è¡ |
| | | .FirstOrDefault(); |
| | | } |
| | | |
| | |
| | | /// <param name="layer">屿°</param> |
| | | /// <param name="depth">深度</param> |
| | | /// <returns>è´§ä½ä¿¡æ¯å¯¹è±¡</returns> |
| | | private static Dt_LocationInfo CreateLocationInfo(string roadwayNo, int row, int col, int layer, int depth) |
| | | private Dt_LocationInfo CreateLocationInfo(string roadwayNo, int row, int col, int layer, int depth) |
| | | { |
| | | var warehouse = _warehouseRepository.QueryData(x => x.WarehouseCode == roadwayNo).FirstOrDefault(); |
| | | |
| | | if (warehouse == null) |
| | | { |
| | | throw new InvalidOperationException($"æªæ¾å°å··éç¼å·ä¸º {roadwayNo} çä»åºä¿¡æ¯"); |
| | | } |
| | | |
| | | return new Dt_LocationInfo |
| | | { |
| | | WarehouseId = 0, |
| | | WarehouseId = warehouse.WarehouseId, |
| | | Row = row, |
| | | Column = col, |
| | | Layer = layer, |
| | |
| | | EnableStatus = EnableStatusEnum.Normal.GetHashCode(), |
| | | LocationStatus = LocationStatusEnum.Free.GetHashCode(), |
| | | LocationType = LocationTypeEnum.Undefined.GetHashCode(), |
| | | LocationCode = $"{row:D3}-{col:D3}-{layer:D3}", |
| | | LocationCode = $"{roadwayNo}-{row:D3}-{col:D3}-{layer:D3}", |
| | | LocationName = $"{roadwayNo}å··é{row:D3}è¡{col:D3}å{layer:D3}å±{depth:D2}æ·±" |
| | | }; |
| | | } |
| | |
| | | public string TargetAddress { get; set; } |
| | | |
| | | /// <summary> |
| | | /// å½åä½ç½® |
| | | /// </summary> |
| | | public string CurrentAddress { get; set; } |
| | | |
| | | /// <summary> |
| | | /// ä¸ä¸å°å |
| | | /// </summary> |
| | | public string NextAddress { get; set; } |
| | | |
| | | /// <summary> |
| | | /// ä¼å
级 |
| | | /// </summary> |
| | | public int Grade { get; set; } |
| | |
| | | public int PalletType { get; set; } |
| | | |
| | | } |
| | | } |
| | | } |
| | |
| | | public Task<WebResponseContent> OutTaskComplete(OutTaskCompleteDto outTaskCompleteDto); |
| | | |
| | | /// <summary> |
| | | /// ä»»å¡å®ææ¥å£ |
| | | /// </summary> |
| | | /// <param name="wCSTask"></param> |
| | | /// <returns></returns> |
| | | //public Task<WebResponseContent> TaskCompleted(WCSTaskDTO wCSTask); |
| | | |
| | | /// <summary> |
| | | /// ä»»å¡åæ¶ |
| | | /// </summary> |
| | | /// <param name="taskCancelDto">请æ±åæ°</param> |
| | | /// <returns></returns> |
| | | public Task<AGVResponse> TaskCancelAsync(TaskCancelDto taskCancelDto); |
| | | |
| | | /// <summary> |
| | | /// åæ¾è´§å®æ |
| | | /// </summary> |
| | | /// <param name="taskCompleteDto">请æ±åæ°</param> |
| | | /// <returns></returns> |
| | | public Task<AGVResponse> TaskCompleteAsync(TaskCompleteDto taskCompleteDto); |
| | | |
| | | /// <summary> |
| | | /// è¾é线ç³è¯·è¿å
¥ |
| | | /// </summary> |
| | |
| | | |
| | | #endregion æå·åºä»»å¡æ¨¡å |
| | | } |
| | | } |
| | | } |
| | |
| | | List<object> data = new List<object>(); |
| | | |
| | | { |
| | | Type type = typeof(TaskTypeEnum); |
| | | List<int> enums = Enum.GetValues(typeof(TaskTypeEnum)).Cast<int>().ToList(); |
| | | Type type = typeof(TaskInboundTypeEnum); |
| | | List<int> enums = Enum.GetValues(typeof(TaskInboundTypeEnum)).Cast<int>().ToList(); |
| | | int index = 0; |
| | | foreach (var item in enums) |
| | | { |
| | | FieldInfo? fieldInfo = typeof(TaskTypeEnum).GetField(((TaskTypeEnum)item).ToString()); |
| | | FieldInfo? fieldInfo = typeof(TaskInboundTypeEnum).GetField(((TaskInboundTypeEnum)item).ToString()); |
| | | DescriptionAttribute? description = fieldInfo.GetCustomAttribute<DescriptionAttribute>(); |
| | | if (description != null) |
| | | { |
| | |
| | | } |
| | | } |
| | | |
| | | { |
| | | Type type = typeof(TaskOutboundTypeEnum); |
| | | List<int> enums = Enum.GetValues(typeof(TaskOutboundTypeEnum)).Cast<int>().ToList(); |
| | | int index = 0; |
| | | foreach (var item in enums) |
| | | { |
| | | FieldInfo? fieldInfo = typeof(TaskOutboundTypeEnum).GetField(((TaskOutboundTypeEnum)item).ToString()); |
| | | DescriptionAttribute? description = fieldInfo.GetCustomAttribute<DescriptionAttribute>(); |
| | | if (description != null) |
| | | { |
| | | data.Add(new { key = item.ToString(), value = description.Description }); |
| | | } |
| | | else |
| | | { |
| | | data.Add(new { key = item.ToString(), value = item.ToString() }); |
| | | } |
| | | index++; |
| | | } |
| | | } |
| | | |
| | | { |
| | | Type type = typeof(TaskRelocationTypeEnum); |
| | | List<int> enums = Enum.GetValues(typeof(TaskRelocationTypeEnum)).Cast<int>().ToList(); |
| | | int index = 0; |
| | | foreach (var item in enums) |
| | | { |
| | | FieldInfo? fieldInfo = typeof(TaskRelocationTypeEnum).GetField(((TaskRelocationTypeEnum)item).ToString()); |
| | | DescriptionAttribute? description = fieldInfo.GetCustomAttribute<DescriptionAttribute>(); |
| | | if (description != null) |
| | | { |
| | | data.Add(new { key = item.ToString(), value = description.Description }); |
| | | } |
| | | else |
| | | { |
| | | data.Add(new { key = item.ToString(), value = item.ToString() }); |
| | | } |
| | | index++; |
| | | } |
| | | } |
| | | |
| | | { |
| | | Type type = typeof(RobotTaskTypeEnum); |
| | | List<int> enums = Enum.GetValues(typeof(RobotTaskTypeEnum)).Cast<int>().ToList(); |
| | | int index = 0; |
| | | foreach (var item in enums) |
| | | { |
| | | FieldInfo? fieldInfo = typeof(RobotTaskTypeEnum).GetField(((RobotTaskTypeEnum)item).ToString()); |
| | | DescriptionAttribute? description = fieldInfo.GetCustomAttribute<DescriptionAttribute>(); |
| | | if (description != null) |
| | | { |
| | | data.Add(new { key = item.ToString(), value = description.Description }); |
| | | } |
| | | else |
| | | { |
| | | data.Add(new { key = item.ToString(), value = item.ToString() }); |
| | | } |
| | | index++; |
| | | } |
| | | } |
| | | result = new VueDictionaryDTO { DicNo = key, Config = "", Data = data }; |
| | | } |
| | | break; |
| | |
| | | } |
| | | } |
| | | } |
| | | } |
| | | } |
| | |
| | | { |
| | | public partial class TaskService |
| | | { |
| | | #region æå·åºä»»å¡æ¨¡å |
| | | |
| | | public string AGV_OutTaskComplete = WIDESEA_Core.Helper.AppSettings.Configuration["AGV_OutTaskComplete"]; |
| | | public string WCS_ReceiveTask = WIDESEA_Core.Helper.AppSettings.Configuration["WCS_ReceiveTask"]; |
| | | |
| | | /// <summary> |
| | | /// åºå
¥åºç³è¯·ã |
| | | /// æå·åºåºå
¥åºç³è¯· |
| | | /// </summary> |
| | | public async Task<AGVResponse> ApplyInOutAsync(ApplyInOutDto applyInOutDto) |
| | | { |
| | |
| | | if (validationMessage != null) |
| | | return response.Error(validationMessage); |
| | | |
| | | var existingTask = await BaseDal.QueryFirstAsync(x => x.PalletCode == applyInOutDto.TrayNumber); |
| | | var existingTask = await BaseDal.QueryFirstAsync(x => x.PalletCode == applyInOutDto.TrayNumber || x.OrderNo == applyInOutDto.TaskId); |
| | | if (existingTask != null) |
| | | return response.Error($"WMSå·²æå½åä»»å¡ï¼ä¸å¯éå¤ä¸åï¼ä»»å¡å·ï¼{applyInOutDto.TaskId}"); |
| | | |
| | |
| | | } |
| | | |
| | | /// <summary> |
| | | /// æå¨åºåºå®æåé¦ç»AGVã |
| | | /// æå¨åºåºå®æåé¦ç»AGV |
| | | /// </summary> |
| | | public async Task<WebResponseContent> OutTaskComplete(OutTaskCompleteDto outTaskCompleteDto) |
| | | { |
| | |
| | | return response.Error(httpResponse?.Msg ?? "AGVæ¥å£è°ç¨å¼å¸¸"); |
| | | |
| | | if (!httpResponse.Code) |
| | | return response.Error(string.IsNullOrWhiteSpace(httpResponse.Msg) ? "AGVæ¥å£è°ç¨å¤±è´¥" : httpResponse.Msg); |
| | | return response.Error(string.IsNullOrWhiteSpace(httpResponse.Msg) ? "AGVæ¥å£è°ç¨å¤±è´¥" : httpResponse.Msg); |
| | | |
| | | var syncResult = await CompleteLocalOutboundAfterAgvAckAsync(task); |
| | | return syncResult.Status ? response.OK(httpResponse.Msg) : syncResult; |
| | |
| | | } |
| | | |
| | | /// <summary> |
| | | /// è¾é线ç³è¯·è¿å
¥ã |
| | | /// è¾é线ç³è¯·è¿å
¥ |
| | | /// </summary> |
| | | public async Task<AGVResponse> ApplyEnterAsync(ApplyEnterDto applyEnterDto) |
| | | { |
| | |
| | | } |
| | | |
| | | /// <summary> |
| | | /// åæ¾è´§å®æã |
| | | /// åæ¾è´§å®æ |
| | | /// </summary> |
| | | public async Task<AGVResponse> TaskCompleteAsync(TaskCompleteDto taskCompleteDto) |
| | | { |
| | |
| | | } |
| | | |
| | | /// <summary> |
| | | /// ä»»å¡åæ¶ã |
| | | /// ä»»å¡åæ¶ |
| | | /// </summary> |
| | | public async Task<AGVResponse> TaskCancelAsync(TaskCancelDto taskCancelDto) |
| | | { |
| | |
| | | } |
| | | } |
| | | |
| | | #region åæ°éªè¯ |
| | | private static string? ValidateApplyInOutRequest(ApplyInOutDto dto) |
| | | { |
| | | if (dto == null) return "请æ±åæ°ä¸è½ä¸ºç©º"; |
| | |
| | | if (string.IsNullOrWhiteSpace(dto.TaskId)) return "ä»»å¡å·ä¸è½ä¸ºç©º"; |
| | | return null; |
| | | } |
| | | #endregion åæ°éªè¯ |
| | | |
| | | #region å
·ä½å®ç° |
| | | // åºå
¥åºå
±ç¨åå»ºä»»å¡ |
| | | private Dt_Task BuildAgvTask(ApplyInOutDto dto) |
| | | { |
| | | var task = new Dt_Task |
| | |
| | | return task; |
| | | } |
| | | |
| | | // æå»ºè¿åAGVåºå
¥åºè¯·æ±ä½ |
| | | private AGVDataDto BuildAgvDataDto(Dt_Task task, ApplyInOutDto dto) |
| | | { |
| | | return new AGVDataDto |
| | |
| | | }; |
| | | } |
| | | |
| | | // å
¥åºå建 |
| | | private async Task<AGVResponse?> CreateAgvInboundTaskAsync(Dt_Task task, ApplyInOutDto dto) |
| | | { |
| | | AGVResponse response = new AGVResponse(); |
| | |
| | | return addResult ? null : response.Error("å
¥åºä»»å¡å建失败"); |
| | | } |
| | | |
| | | // åºåºå建 |
| | | private async Task<AGVResponse?> CreateAgvOutboundTaskAsync(Dt_Task task, ApplyInOutDto dto) |
| | | { |
| | | AGVResponse response = new AGVResponse(); |
| | |
| | | if (stockInfo == null) |
| | | return response.Error($"æªæ¾å°æç{dto.TrayNumber}çåºåä¿¡æ¯"); |
| | | |
| | | if (stockInfo.WarehouseId != dto.YinYang) |
| | | return response.Error($"æç{dto.TrayNumber}ä¸å±äºå½å{(dto.YinYang == 1 ? "é´æ" : "鳿")}"); |
| | | //if (stockInfo.WarehouseId != dto.YinYang) |
| | | // return response.Error($"æç{dto.TrayNumber}ä¸å±äºå½å{(dto.YinYang == 1 ? "é´æ" : "鳿")}"); |
| | | |
| | | if (stockInfo.StockStatus != (int)StockStatusEmun.å
¥åºå®æ) |
| | | return response.Error($"æç{dto.TrayNumber}æ£å¨ç§»å¨ä¸ï¼è¯·ç¨åï¼"); |
| | | |
| | | var locationInfo = await _locationInfoService.GetLocationInfoAsync(stockInfo.LocationCode); |
| | | var locationInfo = await _locationInfoService.GetLocationInfo(stockInfo.LocationCode); |
| | | if (locationInfo == null) |
| | | return response.Error($"æªæ¾å°æç{stockInfo.LocationCode}çè´§ä½ä¿¡æ¯"); |
| | | |
| | |
| | | task.SourceAddress = stockInfo.LocationCode; |
| | | task.CurrentAddress = stockInfo.LocationCode; |
| | | task.TargetAddress = dto.YinYang == 1 ? "D10020" : "D10090"; |
| | | |
| | | var wmsTaskDto = _mapper.Map<WMSTaskDTO>(task); |
| | | var taskList = new List<WMSTaskDTO> { wmsTaskDto }; |
| | | var requestBody = JsonSerializer.Serialize(taskList); |
| | | |
| | | var httpResponse = _httpClientHelper.Post<WebResponseContent>(WCS_ReceiveTask, requestBody); |
| | | if (httpResponse == null || httpResponse.Data == null || !httpResponse.Data.Status) |
| | | return response.Error(httpResponse?.Data?.Message ?? "ä¸åWCS失败"); |
| | | |
| | | stockInfo.StockStatus = (int)StockStatusEmun.åºåºéå®; |
| | | locationInfo.LocationStatus = (int)LocationStatusEnum.InStockLock; |
| | |
| | | _unitOfWorkManage.RollbackTran(); |
| | | return response.Error("åºåºä»»å¡å建失败"); |
| | | } |
| | | |
| | | _unitOfWorkManage.CommitTran(); |
| | | |
| | | |
| | | return null; |
| | | } |
| | | |
| | | private async Task<WebResponseContent> CompleteLocalOutboundAfterAgvAckAsync(Dt_Task task) |
| | | { |
| | | var stockInfo = await _stockInfoService.GetStockInfoAsync(task.PalletCode); |
| | | if (stockInfo == null) |
| | | return WebResponseContent.Instance.Error($"æªæ¾å°æç{task.PalletCode}çåºåä¿¡æ¯"); |
| | | |
| | | var locationInfo = await _locationInfoService.GetLocationInfoAsync(stockInfo.LocationCode); |
| | | if (locationInfo == null) |
| | | return WebResponseContent.Instance.Error($"æªæ¾å°æç{stockInfo.LocationCode}çè´§ä½ä¿¡æ¯"); |
| | | |
| | | if (stockInfo.StockStatus != (int)StockStatusEmun.åºåºéå® || locationInfo.LocationStatus != (int)LocationStatusEnum.InStockLock) |
| | | return WebResponseContent.Instance.Error($"å½ååºå{stockInfo.StockStatus}æè
è´§ä½{locationInfo.LocationStatus}ç¶æä¿¡æ¯é误"); |
| | | |
| | | locationInfo.LocationStatus = (int)LocationStatusEnum.Free; |
| | | task.TaskStatus = (int)TaskOutStatusEnum.Line_OutFinish; |
| | | |
| | | _unitOfWorkManage.BeginTran(); |
| | | var deleteTaskResult = BaseDal.DeleteData(task); |
| | | var updateLocationResult = _locationInfoService.UpdateData(locationInfo); |
| | | var deleteStockResult = _stockInfoService.DeleteData(stockInfo); |
| | | if (!deleteTaskResult || !updateLocationResult.Status || !deleteStockResult.Status) |
| | | var updateResult = BaseDal.UpdateData(task); |
| | | if (!updateResult) |
| | | { |
| | | _unitOfWorkManage.RollbackTran(); |
| | | return WebResponseContent.Instance.Error("AGV宿åä¼ åï¼æ¬å°ä»»å¡/åºå/è´§ä½æ´æ°å¤±è´¥"); |
| | | return WebResponseContent.Instance.Error("AGV宿åä¼ åï¼ä»»å¡æ´æ°å¤±è´¥"); |
| | | } |
| | | |
| | | _unitOfWorkManage.CommitTran(); |
| | |
| | | |
| | | private bool CanApplyEnter(Dt_Task task, ApplyEnterDto dto) |
| | | { |
| | | return dto.InOut == 1 |
| | | ? task.TaskType == (int)TaskInboundTypeEnum.Inbound && task.TaskStatus == (int)TaskInStatusEnum.InNew |
| | | : task.TaskType == (int)TaskOutboundTypeEnum.Outbound && task.TaskStatus == (int)TaskStatusEnum.Line_Finish; |
| | | if (dto.InOut == 1) |
| | | { |
| | | var hasExecutingOutTask = BaseDal.QueryFirst(x => x.TaskType == (int)TaskOutboundTypeEnum.Outbound |
| | | && x.TargetAddress == task.SourceAddress |
| | | && (x.TaskStatus == (int)TaskOutStatusEnum.SC_OutExecuting |
| | | || x.TaskStatus == (int)TaskOutStatusEnum.Line_OutExecuting)); |
| | | |
| | | // å¦ææ²¡ææ£å¨æ§è¡çåºåºä»»å¡ï¼åå
许å
¥åº |
| | | return hasExecutingOutTask == null; |
| | | } |
| | | else |
| | | { |
| | | return task.TaskType == (int)TaskOutboundTypeEnum.Outbound |
| | | && task.TaskStatus == (int)TaskStatusEnum.Line_Finish; |
| | | } |
| | | } |
| | | |
| | | // WCSå
¥åºå®æ |
| | | private async Task<WebResponseContent> CompleteAgvInboundTaskAsync(CreateTaskDto taskDto) |
| | | { |
| | | WebResponseContent response = new WebResponseContent(); |
| | | var task = await BaseDal.QueryFirstAsync(x => x.PalletType == taskDto.PalletType); |
| | | if (task == null) |
| | | return response.Error($"没æå½åæç{taskDto.PalletType}å
¥åºä»»å¡"); |
| | | |
| | | var stockInfo = await _stockInfoService.GetStockInfoAsync(task.PalletCode); |
| | | if (stockInfo == null) |
| | | return response.Error($"æªæ¾å°æç{task.PalletCode}çåºåä¿¡æ¯"); |
| | | |
| | | var locationInfo = await _locationInfoService.GetLocationInfoAsync(task.TargetAddress); |
| | | if (locationInfo == null) |
| | | return response.Error($"æªæ¾å°è´§ä½{task.TargetAddress}çä¿¡æ¯"); |
| | | |
| | | if (locationInfo.LocationStatus == (int)LocationStatusEnum.InStock) |
| | | return response.Error($"å½åè´§ä½{locationInfo.LocationStatus}ç¶æä¸æ¯ç©ºé²ç¶æï¼æ æ³å
¥åº"); |
| | | |
| | | // æ´æ°è´§ä½ç¶æä¸ºå ç¨ |
| | | locationInfo.LocationStatus = (int)LocationStatusEnum.InStock; |
| | | task.TaskStatus = (int)TaskInStatusEnum.InFinish; |
| | | stockInfo.StockStatus = (int)StockStatusEmun.å
¥åºå®æ; |
| | | _unitOfWorkManage.BeginTran(); |
| | | var addStockResult = _stockInfoService.UpdateData(stockInfo); |
| | | var updateLocationResult = _locationInfoService.UpdateData(locationInfo); |
| | | BaseDal.DeleteAndMoveIntoHty(task, App.User.UserId == 0 ? OperateTypeEnum.èªå¨å®æ : OperateTypeEnum.äººå·¥å®æ); |
| | | |
| | | if (!addStockResult.Status || !updateLocationResult.Status) |
| | | { |
| | | _unitOfWorkManage.RollbackTran(); |
| | | return response.Error("å
¥åºå®æåï¼æ·»å åºåæè´§ä½æ´æ°å¤±è´¥"); |
| | | } |
| | | |
| | | _unitOfWorkManage.CommitTran(); |
| | | return response.OK(); |
| | | } |
| | | |
| | | // AGVåºåºå®æ |
| | | private async Task<AGVResponse> CompleteAgvOutboundTaskAsync(Dt_Task task) |
| | | { |
| | | AGVResponse response = new AGVResponse(); |
| | |
| | | |
| | | _unitOfWorkManage.BeginTran(); |
| | | var deleteStockResult = _stockInfoService.DeleteData(stockInfo); |
| | | var updateLocationResult = await _locationInfoService.UpdateLocationInfoAsync(locationInfo); |
| | | var updateLocationResult = _locationInfoService.UpdateData(locationInfo); |
| | | BaseDal.DeleteAndMoveIntoHty(task, App.User.UserId == 0 ? OperateTypeEnum.èªå¨å®æ : OperateTypeEnum.äººå·¥å®æ); |
| | | if (!deleteStockResult.Status || !updateLocationResult) |
| | | if (!deleteStockResult.Status || !updateLocationResult.Status) |
| | | { |
| | | _unitOfWorkManage.RollbackTran(); |
| | | return response.Error("åºåºå®æåï¼æ¬å°åºåæè´§ä½æ´æ°å¤±è´¥"); |
| | |
| | | return response.OK(); |
| | | } |
| | | |
| | | // AGVå·²æ¾è´§ï¼åå¤è¾é线å
¥åº |
| | | private async Task<AGVResponse> CompleteAgvInboundTaskAsync(Dt_Task task) |
| | | { |
| | | AGVResponse response = new AGVResponse(); |
| | |
| | | |
| | | task.TargetAddress = availableLocation.LocationCode; |
| | | |
| | | var wcsTaskDto = _mapper.Map<WCSTaskDTO>(task); |
| | | var httpResponse = _httpClientHelper.Post<WebResponseContent>(WCS_ReceiveTask, JsonSerializer.Serialize(wcsTaskDto)); |
| | | var wmsTaskDto = _mapper.Map<WMSTaskDTO>(task); |
| | | var taskList = new List<WMSTaskDTO> { wmsTaskDto }; |
| | | var requestBody = JsonSerializer.Serialize(taskList); |
| | | |
| | | var httpResponse = _httpClientHelper.Post<WebResponseContent>(WCS_ReceiveTask, requestBody); |
| | | if (httpResponse == null || httpResponse.Data == null || !httpResponse.Data.Status) |
| | | return response.Error(httpResponse?.Data?.Message ?? "ä¸åWCS失败"); |
| | | |
| | | task.TaskStatus = (int)TaskStatusEnum.Line_Executing; |
| | | task.TaskStatus = (int)TaskInStatusEnum.Line_InExecuting; |
| | | task.Dispatchertime = DateTime.Now; |
| | | |
| | | var locationInfo = await _locationInfoService.GetLocationInfoAsync(task.TargetAddress); |
| | |
| | | |
| | | if (locationInfo.LocationStatus != (int)LocationStatusEnum.Free) |
| | | return response.Error($"å½åè´§ä½{locationInfo.LocationStatus}ç¶æä¿¡æ¯é误"); |
| | | |
| | | var existingStock = await _stockInfoService.GetStockInfoAsync(task.PalletCode); |
| | | if (existingStock != null) |
| | | return response.Error($"æç{task.PalletCode}çåºåä¿¡æ¯å·²åå¨ï¼è¯·å¿éå¤å
¥åº"); |
| | | |
| | | Dt_StockInfo stockInfo = new Dt_StockInfo |
| | | { |
| | |
| | | return response.OK(); |
| | | } |
| | | |
| | | // AGVå
¥åºåæ¶ |
| | | private AGVResponse CancelAgvInboundTask(Dt_Task task) |
| | | { |
| | | AGVResponse response = new AGVResponse(); |
| | |
| | | return response.OK(); |
| | | } |
| | | |
| | | |
| | | // AGVåºåºåæ¶ |
| | | private async Task<AGVResponse> CancelAgvOutboundTaskAsync(Dt_Task task) |
| | | { |
| | | AGVResponse response = new AGVResponse(); |
| | |
| | | return response.OK(); |
| | | } |
| | | |
| | | #endregion æå·åºä»»å¡æ¨¡å |
| | | #endregion å
·ä½å®ç° |
| | | } |
| | | } |
| | | } |
| | |
| | | if (stockInfo == null) return WebResponseContent.Instance.Error("æªæ¾å°å¯¹åºåºåä¿¡æ¯"); |
| | | |
| | | // 夿æ¯ä¸æ¯æå·åºä»»å¡ |
| | | //if (taskDto.WarehouseId == (int)WarehouseEnum.FJ1 || taskDto.WarehouseId == (int)WarehouseEnum.ZJ1) |
| | | //{ |
| | | // return WebResponseContent.Instance.OK(); |
| | | //} |
| | | if (taskDto.WarehouseId == (int)WarehouseEnum.FJ1 || taskDto.WarehouseId == (int)WarehouseEnum.ZJ1) |
| | | { |
| | | |
| | | return await CompleteAgvInboundTaskAsync(taskDto); |
| | | } |
| | | |
| | | return await ExecuteWithinTransactionAsync(async () => |
| | | { |
| | |
| | | |
| | | #endregion WCSé»è¾å¤ç |
| | | } |
| | | } |
| | | } |
| | |
| | | /// </summary> |
| | | /// <param name="taskDto"></param> |
| | | /// <returns></returns> |
| | | [HttpGet, HttpPost, Route("CreateTaskInbound"),AllowAnonymous] |
| | | [HttpGet, HttpPost, Route("CreateTaskInbound"), AllowAnonymous] |
| | | public async Task<WebResponseContent?> CreateTaskInboundAsync([FromBody] CreateTaskDto taskDto) |
| | | { |
| | | return await Service.CreateTaskInboundAsync(taskDto); |
| | |
| | | { |
| | | return await Service.ApplyInOutAsync(applyInOutDto); |
| | | } |
| | | |
| | | /// <summary> |
| | | /// æå¨åºåºå®æåé¦ç»AGV |
| | | /// </summary> |
| | |
| | | { |
| | | return await Service.OutTaskComplete(outTaskCompleteDto); |
| | | } |
| | | ///// <summary> |
| | | ///// ä»»å¡å®æ |
| | | ///// </summary> |
| | | ///// <param name="wCSTask">请æ±åæ°</param> |
| | | ///// <returns></returns> |
| | | //[HttpPost, Route("TaskCompleted"), AllowAnonymous] |
| | | //public async Task<WebResponseContent?> TaskCompleted([FromBody] WCSTaskDTO wCSTask) |
| | | //{ |
| | | // return await Service.TaskCompleted(wCSTask); |
| | | //} |
| | | |
| | | /// <summary> |
| | | /// è¾é线ç³è¯·è¿å
¥ |
| | | /// </summary> |
| | |
| | | { |
| | | return await Service.TaskCancelAsync(taskCancelDto); |
| | | } |
| | | |
| | | #endregion æå·åºä»»å¡æ¨¡å |
| | | } |
| | | } |
| | | } |
| | |
| | | "MainDB": "DB_WIDESEA", //å½å项ç®ç主åºï¼æå¯¹åºçè¿æ¥å符串çEnabledå¿
须为true |
| | | //è¿æ¥å符串 |
| | | //"ConnectionString": "HTI6FB1H05Krd07mNm9yBCNhofW6edA5zLs9TY~MNthRYW3kn0qKbMIsGp~3yyPDF1YZUCPBQx8U0Jfk4PH~ajNFXVIwlH85M3F~v_qKYQ3CeAz3q1mLVDn8O5uWt1~3Ut2V3KRkEwYHvW2oMDN~QIDXPxDgXN0R2oTIhc9dNu7QNaLEknblqmHhjaNSSpERdDVZIgHnMKejU_SL49tralBkZmDNi0hmkbL~837j1NWe37u9fJKmv91QPb~16JsuI9uu0EvNZ06g6PuZfOSAeFH9GMMIZiketdcJG3tHelo=", |
| | | "ConnectionString": "Data Source=.;Initial Catalog=WIDESEAWMS_ShanMei;User ID=sa;Password=P@ssw0rd;Integrated Security=False;Connect Timeout=30;Encrypt=False;TrustServerCertificate=False;ApplicationIntent=ReadWrite;MultiSubnetFailover=False", |
| | | //"ConnectionString": "Data Source=.;Initial Catalog=WIDESEAWMS_ShanMei;User ID=sa;Password=123456;Integrated Security=False;Connect Timeout=30;Encrypt=False;TrustServerCertificate=False;ApplicationIntent=ReadWrite;MultiSubnetFailover=False", |
| | | //"ConnectionString": "Data Source=.;Initial Catalog=WIDESEAWMS_ShanMei;User ID=sa;Password=P@ssw0rd;Integrated Security=False;Connect Timeout=30;Encrypt=False;TrustServerCertificate=False;ApplicationIntent=ReadWrite;MultiSubnetFailover=False", |
| | | "ConnectionString": "Data Source=.;Initial Catalog=WIDESEAWMS_ShanMei;User ID=sa;Password=123456;Integrated Security=False;Connect Timeout=30;Encrypt=False;TrustServerCertificate=False;ApplicationIntent=ReadWrite;MultiSubnetFailover=False", |
| | | //"ConnectionString": "Data Source=10.30.4.92;Initial Catalog=WMS_TC;User ID=sa;Password=duo123456;Integrated Security=False;Connect Timeout=30;Encrypt=False;TrustServerCertificate=False;ApplicationIntent=ReadWrite;MultiSubnetFailover=False", |
| | | //æ§WMSæ°æ®åºè¿æ¥ |
| | | //"TeConnectionString": "Data Source=10.30.4.92;Initial Catalog=TeChuang;User ID=sa;Password=duo123456;Integrated Security=False;Connect Timeout=30;Encrypt=False;TrustServerCertificate=False;ApplicationIntent=ReadWrite;MultiSubnetFailover=False", |