From ad18b0c17b5b1f715c33cb2a2b39589c10434a00 Mon Sep 17 00:00:00 2001 From: wanshenmean <cathay_xy@163.com> Date: 星期六, 09 十一月 2024 13:24:48 +0800 Subject: [PATCH] 11.09-1申请巷道与申请货位拆分 --- Code Management/WCS/WIDESEAWCS_Server/WIDESEAWCS_Tasks/ConveyorLineJob/CommonConveyorLineJob.cs | 38 --------- Code Management/WMS/WIDESEA_WMSServer/WIDESEA_StoragIntegrationServices/MOM/AgingInOrOutInput/AgingInOrOutInputService.cs | 2 Code Management/WMS/WIDESEA_WMSServer/WIDESEA_StorageTaskServices/Task/Dt_TaskService.cs | 98 ++++++++++++++++++++++-- Code Management/WCS/WIDESEAWCS_Client/src/extension/quartzJob/deviceInfo.js | 2 Code Management/WCS/WIDESEAWCS_Server/WIDESEAWCS_DTO/WMS/RequestTaskDto.cs | 13 +- Code Management/WMS/WIDESEA_WMSServer/WIDESEA_IStorageTaskService/Task/IDt_TaskService.cs | 10 ++ Code Management/WMS/WIDESEA_WMSServer/WIDESEA_WMSServer/Controllers/TaskController.cs | 14 +++ Code Management/WCS/WIDESEAWCS_Server/WIDESEAWCS_TaskInfoService/TaskService.cs | 13 ++- Code Management/WMS/WIDESEA_WMSServer/WIDESEA_DTO/Basic/RequestTaskDto.cs | 5 + Code Management/WCS/WIDESEAWCS_Client/src/api/http.js | 2 Code Management/WCS/WIDESEAWCS_Server/WIDESEAWCS_Tasks/ConveyorLineJob/Task/RequestInbound.cs | 6 + Code Management/WCS/WIDESEAWCS_Server/WIDESEAWCS_Core/Helper/HttpHelper.cs | 6 + 12 files changed, 143 insertions(+), 66 deletions(-) diff --git a/Code Management/WCS/WIDESEAWCS_Client/src/api/http.js b/Code Management/WCS/WIDESEAWCS_Client/src/api/http.js index c81ff8f..c648172 100644 --- a/Code Management/WCS/WIDESEAWCS_Client/src/api/http.js +++ b/Code Management/WCS/WIDESEAWCS_Client/src/api/http.js @@ -19,7 +19,7 @@ } else if (process.env.NODE_ENV == 'production') { - axios.defaults.baseURL = 'http://115.159.85.185:9291/'; + axios.defaults.baseURL = 'http://127.0.0.1:9291/'; } if (!axios.defaults.baseURL.endsWith('/')) { axios.defaults.baseURL+="/"; diff --git a/Code Management/WCS/WIDESEAWCS_Client/src/extension/quartzJob/deviceInfo.js b/Code Management/WCS/WIDESEAWCS_Client/src/extension/quartzJob/deviceInfo.js index e700d90..d882861 100644 --- a/Code Management/WCS/WIDESEAWCS_Client/src/extension/quartzJob/deviceInfo.js +++ b/Code Management/WCS/WIDESEAWCS_Client/src/extension/quartzJob/deviceInfo.js @@ -31,7 +31,7 @@ icon: "el-icon-document", //鎸夐挳鍥炬爣vue2鐗堟湰瑙乮view鏂囨。icon锛寁ue3鐗堟湰瑙乪lement ui鏂囨。icon(娉ㄦ剰涓嶆槸element puls鏂囨。) type: "primary", //鎸夐挳鏍峰紡vue2鐗堟湰瑙乮view鏂囨。button锛寁ue3鐗堟湰瑙乪lement ui鏂囨。button onClick: function () { - this.$Message.success("鐐瑰嚮浜嗘寜閽�"); + this.$Message.success("寮�鍚湇鍔�"); }, }); }, diff --git a/Code Management/WCS/WIDESEAWCS_Server/WIDESEAWCS_Core/Helper/HttpHelper.cs b/Code Management/WCS/WIDESEAWCS_Server/WIDESEAWCS_Core/Helper/HttpHelper.cs index 91d5f89..d6982b4 100644 --- a/Code Management/WCS/WIDESEAWCS_Server/WIDESEAWCS_Core/Helper/HttpHelper.cs +++ b/Code Management/WCS/WIDESEAWCS_Server/WIDESEAWCS_Core/Helper/HttpHelper.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.Linq; using System.Net.Http.Headers; +using System.Security.Policy; using System.Text; using System.Threading.Tasks; @@ -9,13 +10,16 @@ { public class HttpHelper { - public static async Task<string> GetAsync(string serviceAddress, string contentType = "application/json", Dictionary<string, string>? headers = null) + public static async Task<string> GetAsync(string serviceAddress, Dictionary<string, object> parameters, string contentType = "application/json", Dictionary<string, string>? headers = null) { try { string result = string.Empty; using HttpClient httpClient = new HttpClient(); httpClient.Timeout = new TimeSpan(0, 0, 60); + // 灏嗗弬鏁版嫾鎺ュ埌URL涓� + string queryString = string.Join("&", parameters.Select(x => $"{x.Key}={x.Value}")); + serviceAddress += "?" + queryString; if (headers != null) { diff --git a/Code Management/WCS/WIDESEAWCS_Server/WIDESEAWCS_DTO/WMS/RequestTaskDto.cs b/Code Management/WCS/WIDESEAWCS_Server/WIDESEAWCS_DTO/WMS/RequestTaskDto.cs index 320f70e..91dc7b9 100644 --- a/Code Management/WCS/WIDESEAWCS_Server/WIDESEAWCS_DTO/WMS/RequestTaskDto.cs +++ b/Code Management/WCS/WIDESEAWCS_Server/WIDESEAWCS_DTO/WMS/RequestTaskDto.cs @@ -1,10 +1,4 @@ -锘縰sing System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace WIDESEAWCS_DTO.WMS +锘縩amespace WIDESEAWCS_DTO.WMS { public class RequestTaskDto { @@ -22,5 +16,10 @@ /// 绌烘墭鐩樺彲鍏ュ贩鍒� /// </summary> public string PositionList { get; set; } + + /// <summary> + /// 浠诲姟绫诲瀷 + /// </summary> + public string RequestType { get; set; } = string.Empty; } } \ No newline at end of file diff --git a/Code Management/WCS/WIDESEAWCS_Server/WIDESEAWCS_TaskInfoService/TaskService.cs b/Code Management/WCS/WIDESEAWCS_Server/WIDESEAWCS_TaskInfoService/TaskService.cs index 71e16ac..830c4ce 100644 --- a/Code Management/WCS/WIDESEAWCS_Server/WIDESEAWCS_TaskInfoService/TaskService.cs +++ b/Code Management/WCS/WIDESEAWCS_Server/WIDESEAWCS_TaskInfoService/TaskService.cs @@ -132,7 +132,7 @@ WebResponseContent content = new WebResponseContent(); try { - #region 鐪熷疄鏁版嵁 + #region 璇锋眰鍏ュ簱浠诲姟宸烽亾 // TODO: 璋冪敤鎺ュ彛鑾峰彇涓嬩竴涓湴鍧� // 鍒涘缓璇锋眰瀵硅薄 RequestTaskDto request = new RequestTaskDto() @@ -429,7 +429,7 @@ if (task.TaskState == (int)TaskInStatusEnum.Line_InFinish) { - #region 鐪熷疄鏁版嵁 + #region 鍏ュ簱璋冪敤鎺ュ彛鑾峰彇璐т綅鍦板潃 // TODO: 璋冪敤鎺ュ彛鑾峰彇璐т綅鍦板潃 // 鍒涘缓璇锋眰瀵硅薄 RequestTaskDto taskDto = new RequestTaskDto() @@ -439,7 +439,7 @@ }; // 鍙戦�佽姹傚苟绛夊緟鍝嶅簲 - var abc = HttpHelper.PostAsync("http://127.0.0.1:5000/api/Task/RequestTaskAsync", taskDto.ToJsonString()).Result; + var abc = HttpHelper.PostAsync("http://127.0.0.1:5000/api/Task/RequestLocationTaskAsync", taskDto.ToJsonString()).Result; if (abc == null) return content.Error(); // 鍙嶅簭鍒楀寲鍝嶅簲鍐呭 @@ -586,8 +586,11 @@ #region WMS鍚屾浠诲姟瀹屾垚 - //var x = new { taskNum = taskNum }; - var result = HttpHelper.GetAsync($"http://127.0.0.1:5000/api/Task/CompleteTaskAsync?taskNum={taskNum}").Result; + var keys = new Dictionary<string, object>() + { + {"taskNum", taskNum} + }; + var result = HttpHelper.GetAsync($"http://127.0.0.1:5000/api/Task/CompleteTaskAsync", keys).Result; content = JsonConvert.DeserializeObject<WebResponseContent>(result); #endregion #region 鏇存柊浠诲姟鐘舵�� diff --git a/Code Management/WCS/WIDESEAWCS_Server/WIDESEAWCS_Tasks/ConveyorLineJob/CommonConveyorLineJob.cs b/Code Management/WCS/WIDESEAWCS_Server/WIDESEAWCS_Tasks/ConveyorLineJob/CommonConveyorLineJob.cs index 16dccc6..ced741e 100644 --- a/Code Management/WCS/WIDESEAWCS_Server/WIDESEAWCS_Tasks/ConveyorLineJob/CommonConveyorLineJob.cs +++ b/Code Management/WCS/WIDESEAWCS_Server/WIDESEAWCS_Tasks/ConveyorLineJob/CommonConveyorLineJob.cs @@ -313,7 +313,7 @@ /// <summary> - /// 闄堝寲绌烘墭鐩樺嚭搴� + /// 鐩戞祴绌烘墭鐩樺疄鐩樺嚭搴� /// </summary> /// <param name="conveyorLine">杈撻�佺嚎瀹炰緥瀵硅薄</param> /// <param name="command">璇诲彇鐨勮姹備俊鎭�</param> @@ -335,42 +335,6 @@ } } - - #region - ///// <summary> - ///// 闄堝寲瀹炵洏鍑哄簱) - ///// </summary> - ///// <param name="conveyorLine">杈撻�佺嚎瀹炰緥瀵硅薄</param> - ///// <param name="command">璇诲彇鐨勮姹備俊鎭�</param> - ///// <param name="childDeviceCode">瀛愯澶囩紪鍙�</param> - ///// <param name="index">绾夸綋褰撳墠bool璇诲彇鍋忕Щ鍦板潃</param> - //public void ChuanhuaOutbound(CommonConveyorLine conveyorLine, ConveyorLineTaskCommand command, string childDeviceCode) - //{ - // CheckAndCreateTask(TaskOutboundTypeEnum.Outbound, childDeviceCode, "CHSC01", "001-001-001"); - //} - - ///// 闈欑疆绌烘墭鐩樺嚭搴� - ///// </summary> - ///// <param name="conveyorLine">杈撻�佺嚎瀹炰緥瀵硅薄</param> - ///// <param name="command">璇诲彇鐨勮姹備俊鎭�</param> - ///// <param name="childDeviceCode">瀛愯澶囩紪鍙�</param> - ///// <param name="index">绾夸綋褰撳墠bool璇诲彇鍋忕Щ鍦板潃</param> - //public void EmptyTrayOutbound(CommonConveyorLine conveyorLine, ConveyorLineTaskCommand command, string childDeviceCode, int index) - //{ - // CheckAndCreateTask(TaskOutboundTypeEnum.OutTray, childDeviceCode, index, "JZSC01", "002-020-001"); - //} - ///// <summary> - ///// 闈欑疆瀹炵洏鍑哄簱 - ///// </summary> - ///// <param name="conveyorLine">杈撻�佺嚎瀹炰緥瀵硅薄</param> - ///// <param name="command">璇诲彇鐨勮姹備俊鎭�</param> - ///// <param name="childDeviceCode">瀛愯澶囩紪鍙�</param> - ///// <param name="index">绾夸綋褰撳墠bool璇诲彇鍋忕Щ鍦板潃</param> - //public void JingzhiOutbound(CommonConveyorLine conveyorLine, ConveyorLineTaskCommand command, string childDeviceCode, int index) - //{ - // CheckAndCreateTask(TaskOutboundTypeEnum.Outbound, childDeviceCode, index, "JZSC01", "002-000-001"); - //} - #endregion /// <summary> /// 妫�鏌ヤ换鍔″苟鍒涘缓鏂颁换鍔� diff --git a/Code Management/WCS/WIDESEAWCS_Server/WIDESEAWCS_Tasks/ConveyorLineJob/Task/RequestInbound.cs b/Code Management/WCS/WIDESEAWCS_Server/WIDESEAWCS_Tasks/ConveyorLineJob/Task/RequestInbound.cs index a6424b2..78f336f 100644 --- a/Code Management/WCS/WIDESEAWCS_Server/WIDESEAWCS_Tasks/ConveyorLineJob/Task/RequestInbound.cs +++ b/Code Management/WCS/WIDESEAWCS_Server/WIDESEAWCS_Tasks/ConveyorLineJob/Task/RequestInbound.cs @@ -97,7 +97,11 @@ } // TODO璋冪敤WMS浠诲姟瀹屾垚鎺ュ彛 - var result = HttpHelper.GetAsync($"http://127.0.0.1:5000/api/Task/CompleteTaskAsync?taskNum={taskOut.TaskNum}").Result; + var keys = new Dictionary<string, object>() + { + {"taskNum", taskOut.TaskNum} + }; + var result = HttpHelper.GetAsync($"http://127.0.0.1:5000/api/Task/CompleteTaskAsync", keys).Result; WebResponseContent content = JsonConvert.DeserializeObject<WebResponseContent>(result); if (content.Status) { diff --git a/Code Management/WMS/WIDESEA_WMSServer/WIDESEA_DTO/Basic/RequestTaskDto.cs b/Code Management/WMS/WIDESEA_WMSServer/WIDESEA_DTO/Basic/RequestTaskDto.cs index 8ca8d59..63a5ce1 100644 --- a/Code Management/WMS/WIDESEA_WMSServer/WIDESEA_DTO/Basic/RequestTaskDto.cs +++ b/Code Management/WMS/WIDESEA_WMSServer/WIDESEA_DTO/Basic/RequestTaskDto.cs @@ -16,6 +16,11 @@ /// 绌烘墭鐩樺彲鍏ュ贩鍒� /// </summary> public string PositionList { get; set; } + + /// <summary> + /// 浠诲姟绫诲瀷 + /// </summary> + public string RequestType { get; set; } = string.Empty; } public class RequestOutTaskDto diff --git a/Code Management/WMS/WIDESEA_WMSServer/WIDESEA_IStorageTaskService/Task/IDt_TaskService.cs b/Code Management/WMS/WIDESEA_WMSServer/WIDESEA_IStorageTaskService/Task/IDt_TaskService.cs index 7b13658..c63e2d2 100644 --- a/Code Management/WMS/WIDESEA_WMSServer/WIDESEA_IStorageTaskService/Task/IDt_TaskService.cs +++ b/Code Management/WMS/WIDESEA_WMSServer/WIDESEA_IStorageTaskService/Task/IDt_TaskService.cs @@ -124,7 +124,7 @@ Task<WebResponseContent> CompleteAsync(int taskNum); /// <summary> - /// 璇锋眰浠诲姟 + /// 璇锋眰浠诲姟宸烽亾 /// </summary> /// <param name="position"></param> /// <param name="areaCode"></param> @@ -132,6 +132,13 @@ /// <param name="type"></param> /// <returns></returns> Task<WebResponseContent> RequestTaskAsync(RequestTaskDto input); + + /// <summary> + /// 璇锋眰浠诲姟璐т綅 + /// </summary> + /// <param name="input"></param> + /// <returns></returns> + Task<WebResponseContent> UpdateExistingTask(RequestTaskDto input); /// <summary> /// 璇锋眰绌烘墭鐩樹换鍔� @@ -157,4 +164,5 @@ /// <param name="input">璇锋眰鏁版嵁</param> /// <returns></returns> Task<WebResponseContent> UpdateTaskStatus(int taskNum, int taskState); + } \ No newline at end of file diff --git a/Code Management/WMS/WIDESEA_WMSServer/WIDESEA_StoragIntegrationServices/MOM/AgingInOrOutInput/AgingInOrOutInputService.cs b/Code Management/WMS/WIDESEA_WMSServer/WIDESEA_StoragIntegrationServices/MOM/AgingInOrOutInput/AgingInOrOutInputService.cs index b4b7cc5..b33d0ed 100644 --- a/Code Management/WMS/WIDESEA_WMSServer/WIDESEA_StoragIntegrationServices/MOM/AgingInOrOutInput/AgingInOrOutInputService.cs +++ b/Code Management/WMS/WIDESEA_WMSServer/WIDESEA_StoragIntegrationServices/MOM/AgingInOrOutInput/AgingInOrOutInputService.cs @@ -53,7 +53,7 @@ { input.SessionId = Guid.NewGuid().ToString(); input.EmployeeNo = "T00001"; - input.RequestTime = TimeZoneInfo.ConvertTimeToUtc(DateTime.Now).ToString("yyyy-MM-ddTHH:mm:ss.fffZ"); ; + input.RequestTime = TimeZoneInfo.ConvertTimeToUtc(DateTime.Now).ToString("yyyy-MM-ddTHH:mm:ss.fffZ"); var inputJson = input.ToDictionary(); var x = await HttpsClient.PostAsync("http://ts-momapp01:12020/api/MachineIntegration/AgingOutput", inputJson); content.OK(data: x); diff --git a/Code Management/WMS/WIDESEA_WMSServer/WIDESEA_StorageTaskServices/Task/Dt_TaskService.cs b/Code Management/WMS/WIDESEA_WMSServer/WIDESEA_StorageTaskServices/Task/Dt_TaskService.cs index cd77752..5367dc9 100644 --- a/Code Management/WMS/WIDESEA_WMSServer/WIDESEA_StorageTaskServices/Task/Dt_TaskService.cs +++ b/Code Management/WMS/WIDESEA_WMSServer/WIDESEA_StorageTaskServices/Task/Dt_TaskService.cs @@ -401,7 +401,7 @@ #region 璇锋眰浠诲姟鍏ュ簱 /// <summary> - /// 璇锋眰浠诲姟 + /// 璇锋眰浠诲姟宸烽亾 /// </summary> /// <param name="input">璇锋眰妯″瀷</param> /// <returns>鍖呭惈浠诲姟淇℃伅鐨勫搷搴斿唴瀹�</returns> @@ -416,7 +416,7 @@ var task = await BaseDal.QueryFirstAsync(x => x.PalletCode == input.PalletCode); if (task != null) { - if (task.TaskState == (int)TaskInStatusEnum.InNew) + //if (task.TaskState == (int)TaskInStatusEnum.InNew) { // 鍒涘缓WMS浠诲姟 WMSTaskDTO taskDTO = new WMSTaskDTO() @@ -433,8 +433,6 @@ }; return content.OK(data: taskDTO); } - content = await UpdateExistingTask(input, task); - return content; } // 鍒涘缓涓�涓猅rayCellsStatusDto瀵硅薄锛屽苟璧嬪�� TrayCellsStatusDto trayCells = new TrayCellsStatusDto() @@ -465,8 +463,8 @@ // 璋冪敤GetProcessResponseAsync鏂规硶锛岃幏鍙栧伐鑹哄搷搴� var processResponse = await GetProcessResponseAsync(process, input.Position); - // 濡傛灉task涓嶄负null锛屽垯璋冪敤UpdateExistingTask鏂规硶锛屾洿鏂颁换鍔★紱鍚﹀垯璋冪敤CreateNewTask鏂规硶锛屽垱寤烘柊浠诲姟 - content = task != null ? await UpdateExistingTask(input, task) : await CreateNewTask(input, processResponse); + // 璋冪敤CreateNewTask鏂规硶锛屽垱寤烘柊浠诲姟 + content = await CreateNewTask(input, processResponse); if (content.Status) { var isBox = await _boxingInfoRepository.AddDataNavAsync(boxing); @@ -483,6 +481,35 @@ return content; } + /// <summary> + /// 鏇存柊浠诲姟璐т綅 + /// </summary> + /// <param name="input"></param> + /// <returns></returns> + public async Task<WebResponseContent> UpdateExistingTask(RequestTaskDto input) + { + WebResponseContent content = new WebResponseContent(); + try + { + var task = await BaseDal.QueryFirstAsync(x => x.PalletCode == input.PalletCode); + if (task == null) + return content.Error($"鏆傛湭鎵惧埌銆恵input.PalletCode}銆戠殑浠诲姟"); + + return content = await UpdateExistingTask(input, task); + + } + catch (Exception err) + { + + throw; + } + } + + /// <summary> + /// 绌烘墭鐩樺叆搴撶敵璇� + /// </summary> + /// <param name="input"></param> + /// <returns></returns> public async Task<WebResponseContent> RequestTrayInTaskAsync(RequestTaskDto input) { WebResponseContent content = new WebResponseContent(); @@ -718,6 +745,12 @@ #region 浠诲姟鐘舵�佹洿鏀� + /// <summary> + /// 鏇存柊浠诲姟鐘舵��&鍑哄簱瑙g洏 + /// </summary> + /// <param name="taskNum"></param> + /// <param name="taskState"></param> + /// <returns></returns> public async Task<WebResponseContent> UpdateTaskStatus(int taskNum, int taskState) { WebResponseContent content = new WebResponseContent(); @@ -726,12 +759,57 @@ var task = await BaseDal.QueryFirstAsync(x => x.TaskNum == taskNum); if (task == null) return content.Error("鏈壘鍒颁换鍔�"); - task.TaskState = taskState; - var asb = await BaseDal.UpdateDataAsync(task); - if (asb) + + if (taskState == (int)TaskOutStatusEnum.Line_OutFinish) + { + var taskHty = CreateHistoricalTask(task); + await _unitOfWorkManage.UseTranAsync(async () => + { + var asb = await BaseDal.DeleteDataByIdAsync(task.TaskId); + var asbHty = await _task_HtyRepository.AddDataAsync(taskHty) > 0; + if (asb && asbHty) + content.OK(); + else + throw new Exception(); + }); content.OK(); + } else - content.Error(); + { + task.TaskState = taskState; + var asb = await BaseDal.UpdateDataAsync(task); + if (asb) + content.OK(); + else + content.Error(); + } + } + catch (Exception ex) + { + content.Error(ex.Message); + } + return content; + } + + #endregion + + #region 鍑哄簱瑙g洏 + + /// <summary> + /// 鍑哄簱瑙g洏鎺ュ彛 + /// </summary> + /// <param name="taskNum"></param> + /// <returns></returns> + public async Task<WebResponseContent> OutUnblockInterface(int taskNum) + { + WebResponseContent content = new WebResponseContent(); + try + { + var task = await BaseDal.QueryFirstAsync(x => x.TaskNum == taskNum); + if (task == null) + return content.Error("鏈壘鍒颁换鍔�"); + task.TaskState = (int)TaskOutStatusEnum.Line_OutFinish; + var taskHty = CreateHistoricalTask(task); } catch (Exception ex) { diff --git a/Code Management/WMS/WIDESEA_WMSServer/WIDESEA_WMSServer/Controllers/TaskController.cs b/Code Management/WMS/WIDESEA_WMSServer/WIDESEA_WMSServer/Controllers/TaskController.cs index 58cf6b7..c804cb4 100644 --- a/Code Management/WMS/WIDESEA_WMSServer/WIDESEA_WMSServer/Controllers/TaskController.cs +++ b/Code Management/WMS/WIDESEA_WMSServer/WIDESEA_WMSServer/Controllers/TaskController.cs @@ -46,7 +46,7 @@ } /// <summary> - /// 浠诲姟璇锋眰 + /// 璇锋眰浠诲姟宸烽亾 /// </summary> /// <param name="input">璇锋眰鏁版嵁</param> /// <returns></returns> @@ -54,6 +54,17 @@ public async Task<WebResponseContent> RequestTaskAsync([FromBody] RequestTaskDto input) { return await Service.RequestTaskAsync(input); + } + + /// <summary> + /// 璇锋眰浠诲姟璐т綅 + /// </summary> + /// <param name="input">璇锋眰鏁版嵁</param> + /// <returns></returns> + [HttpPost, AllowAnonymous, Route("RequestLocationTaskAsync")] + public async Task<WebResponseContent> UpdateExistingTask([FromBody] RequestTaskDto input) + { + return await Service.UpdateExistingTask(input); } /// <summary> @@ -88,4 +99,5 @@ { return await Service.UpdateTaskStatus(input.TaskNum, input.TaskState); } + } \ No newline at end of file -- Gitblit v1.9.3