ÏîÄ¿´úÂë/WIDESEA_WMSClient/config/buttons.js
@@ -363,6 +363,15 @@ type: 'danger', onClick: function () { } }, ,{ name: "åºåè·¨åºåç§»åº", icon: '', class: '', value: 'SelectStockAreaIn', type: 'danger', onClick: function () { } } ] ÏîÄ¿´úÂë/WIDESEA_WMSClient/src/extension/stock/extend/CrossAreaRelocationDialog.vue
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,105 @@ <template> <vol-box v-model="show" title="è·¨åºåç§»åº" :width="800" :height="1200"> <template #content> <el-form ref="form" :model="form" label-width="100px"> <el-form-item label="ç®æ è´§ä½ç±»å:"> <el-select v-model="targetLocationType" placeholder="è¯·éæ©ç®æ è´§ä½ç±»å"> <el-option v-for="item in locationTypes" :key="item.locationType" :label="item.locationTypeDesc.toString()" :value="item.locationType"> </el-option> </el-select> </el-form-item> </el-form> </template> <template #footer> <div> <el-button type="danger" size="small" plain @click="submit" :loading="isSubmitting" :disabled="isSubmitting"> <i class="el-icon-check">确认移åº</i> </el-button> <el-button size="small" type="primary" plain @click="() => { this.show = false }"> <i class="el-icon-close">å ³é</i> </el-button> </div> </template> </vol-box> </template> <script> import VolBox from '@/components/basic/VolBox.vue' export default { components: { 'vol-box': VolBox }, data() { return { show: false, locationTypes: [], targetLocationType: "", isSubmitting: false, form:{} } }, methods: { open() { this.show = true this.getData(); }, submit() { // 1. éªè¯å¿ 填项 if (!this.targetLocationType) { this.$message.warning('è¯·éæ©ç®æ è´§ä½ç±»å'); return; } // 2. ç¦ç¨æé® this.isSubmitting = true; this.$emit('parentCall', ($vue) => { // éä¸çè¡¨æ ¼æ°æ® let stockViews = $vue.$refs.table.getSelected(); this.http.post( `/api/Task/CrossAreaOutbound?targetLocationType=${this.targetLocationType}`, stockViews, 'è·¨åºåç§»åºå¤çä¸...' ) .then((x) => { if (!x.status) { this.$message.error(x.message) } else { this.show = false this.$message.success(x.message || 'è·¨åºåç§»åºä»»å¡çææå') $vue.refresh(); } }) .catch((error) => { this.$message.error('请æ±å¤±è´¥ï¼è¯·ç¨åéè¯'); console.error('è·¨åºåç§»åºå¤±è´¥:', error); }) .finally(() => { this.isSubmitting = false; }); }) }, getData() { this.http.post("api/LocationInfo/GetLocationTypes", null, "å 载货ä½ç±»åä¸") .then((x) => { this.locationTypes = x.data; }) }, } } </script> ÏîÄ¿´úÂë/WIDESEA_WMSClient/src/extension/stock/stockView.js
@@ -1,9 +1,10 @@ import { createVNode, render, h, reactive } from 'vue'; import { ElDialog, ElForm, ElFormItem, ElSelect, ElOption, ElButton, ElMessage, ElLoading } from 'element-plus'; import gridHeader from './extend/CrossAreaRelocationDialog.vue' let extension = { components: { //æ¥è¯¢ç颿©å±ç»ä»¶ gridHeader: '', gridHeader: gridHeader, gridBody: '', gridFooter: '', //æ°å»ºãç¼è¾å¼¹åºæ¡æ©å±ç»ä»¶ @@ -335,6 +336,16 @@ }); } } var SelectStockAreaIn = this.buttons.find(x => x.value == "SelectStockAreaIn"); if (SelectStockAreaIn != null) { SelectStockAreaIn.onClick = () => { let rows = this.$refs.table.getSelected(); if (rows.length == 0) { return this.$message.error("请å éæ©éè¦ç§»åºçæ°æ®ï¼"); } this.$refs.gridHeader.open(); } } }, onInited() { //æ¡æ¶åå§åé ç½®å ÏîÄ¿´úÂë/WIDESEA_WMSClient/src/views/inbound/inboundOrder.vue
@@ -274,7 +274,6 @@ width: 150, align: "left", edit: { type: "" }, required: true, }, { field: "batchNo", @@ -300,6 +299,7 @@ type: "decimal", width: 90, align: "left", edit: { type: "" }, required: true }, { ÏîÄ¿´úÂë/WMSÎÞ²Ö´¢°æ/WIDESEA_WMSServer/WIDESEA_Common/TaskEnum/TaskTypeEnum.cs
@@ -153,7 +153,13 @@ /// ååºåç§»åº /// </summary> [Description("ååºåç§»åº")] AreaRelocation = 910 AreaRelocation = 910, /// <summary> /// è·¨åºåç§»åº /// </summary> [Description("è·¨åºåç§»åº")] CrossAreaRelocation = 920 } ÏîÄ¿´úÂë/WMSÎÞ²Ö´¢°æ/WIDESEA_WMSServer/WIDESEA_ITaskInfoService/ITaskService.cs
@@ -81,5 +81,7 @@ Task<WebResponseContent> TaskCancel(List<int> taskCodes); Task<WebResponseContent> AreaOutbound(List<StockViewDTO> stockViews); Task<WebResponseContent> CrossAreaOutbound(List<StockViewDTO> stockViews, int targetLocationType); } } ÏîÄ¿´úÂë/WMSÎÞ²Ö´¢°æ/WIDESEA_WMSServer/WIDESEA_InboundService/InboundService.cs
@@ -80,7 +80,8 @@ _allocateOrderRepository = allocateOrderRepository; } public async Task<WebResponseContent> GroupPallet(GroupPalletDto palletDto) public async Task<WebResponseContent> GroupPallet(GroupPalletDto palletDto) { WebResponseContent content = new WebResponseContent(); try @@ -180,6 +181,20 @@ stockInfo = new Dt_StockInfo() { PalletType = (int)PalletTypeEnum.None, LocationType = Convert.ToInt32(palletDto.locationType) }; stockInfo.Details = new List<Dt_StockInfoDetail>(); } //else //{ // var allowStatus = new[] // { // (int)StockStatusEmun.ç»çæå, // (int)StockStatusEmun.æºä»å ¥æºä»ç»çæå, // (int)StockStatusEmun.æå¨ç»çæå // }; // if (!allowStatus.Contains(stockInfo.StockStatus)) // { // return content.Error($"该æç{stockInfo.PalletCode}ç¶æä¸å 许ç»ç"); // } //} if (inboundOrder.BusinessType != MESDocumentType.PurchaseInbound.ToString() && stockInfo != null && stockInfo.Details.Count > 0 && stockInfo.Details.FirstOrDefault()?.WarehouseCode != palletDto.WarehouseType) { ÏîÄ¿´úÂë/WMSÎÞ²Ö´¢°æ/WIDESEA_WMSServer/WIDESEA_TaskInfoService/TaskService.cs
@@ -311,7 +311,7 @@ stockInfo.StockStatus = StockStatusEmun.å ¥åºå®æ.ObjToInt(); stockInfo.Details.ForEach(x => { x.Status = StockStatusEmun.å ¥åºç¡®è®¤.ObjToInt(); x.Status = inboundOrders.FirstOrDefault().CreateType == (int)OrderCreateTypeEnum.CreateInSystem ? StockStatusEmun.å ¥åºå®æ.ObjToInt():StockStatusEmun.å ¥åºç¡®è®¤.ObjToInt(); }); _stockService.StockInfoService.Repository.UpdateData(stockInfo); _stockService.StockInfoDetailService.Repository.UpdateData(stockInfo.Details); @@ -2711,6 +2711,138 @@ return await Task.FromResult(WebResponseContent.Instance.Error($"ç§»åºä»»å¡å¤ç失败ï¼{ex.Message}")); } } /// <summary> /// è·¨åºåç§»åºä»»å¡å®æ /// </summary> /// <param name="task"></param> /// <returns></returns> public async Task<WebResponseContent> CrossAreaRelocationTaskCompleted(Dt_Task task) { WebResponseContent content = new WebResponseContent(); try { if (task == null || string.IsNullOrEmpty(task.PalletCode) || string.IsNullOrEmpty(task.TargetAddress)) { return WebResponseContent.Instance.Error("è·¨åºåç§»åºä»»å¡ä¿¡æ¯ä¸å®æ´ï¼æçå·/ç®æ è´§ä½ä¸ºç©ºï¼"); } // 2. æ¥è¯¢æçåºåä¿¡æ¯ Dt_StockInfo stockInfo = await _stockRepository.Db.Queryable<Dt_StockInfo>() .Includes(x => x.Details) .Where(x => x.PalletCode == task.PalletCode) .FirstAsync(); if (stockInfo == null) { return WebResponseContent.Instance.Error($"æªæ¾å°æç[{task.PalletCode}]对åºçåºåä¿¡æ¯"); } // é空æçå¿ é¡»ææç» if (stockInfo.Details.Count == 0 && stockInfo.PalletType != PalletTypeEnum.Empty.ObjToInt()) { _logger.LogInformation($"CrossAreaRelocationTaskCompleted: æªæ¾å°è¯¥æçåºåæç»ä¿¡æ¯.{task.TaskNum}"); return WebResponseContent.Instance.Error($"æªæ¾å°è¯¥æç[{task.PalletCode}]åºåæç»ä¿¡æ¯"); } // 3. æ¥è¯¢ç®æ è´§ä½ + åè´§ä½ä¿¡æ¯ Dt_LocationInfo targetLocationInfo = _locationInfoService.Repository.QueryFirst(x => x.LocationCode == task.TargetAddress); if (targetLocationInfo == null) { return content.Error($"æªæ¾å°å¯¹åºçç»ç¹è´§ä½[{task.TargetAddress}]ä¿¡æ¯"); } // åè´§ä½ä¿¡æ¯ Dt_LocationInfo oldLocationInfo = null; if (!string.IsNullOrEmpty(stockInfo.LocationCode)) { oldLocationInfo = _locationInfoService.Repository.QueryFirst(x => x.LocationCode == stockInfo.LocationCode); if (oldLocationInfo == null) { return content.Error($"æªæ¾å°åè´§ä½[{stockInfo.LocationCode}]ä¿¡æ¯"); } } // 4. è´§ä½ç¶ææ ¡éª if (targetLocationInfo.LocationStatus == LocationStatusEnum.InStock.ObjToInt()) { return WebResponseContent.Instance.Error($"ç®æ è´§ä½[{task.TargetAddress}]ç¶æä¸æ£ç¡®ï¼å½å为已å ç¨ï¼"); } // 5. å¼å¯äºå¡å¤çæ ¸å¿é»è¾ _unitOfWorkManage.BeginTran(); // 5.1 ç®æ è´§ä½æ´æ°ä¸ºå ç¨ var beforeTargetLocationStatus = targetLocationInfo.LocationStatus; targetLocationInfo.LocationStatus = stockInfo.PalletType == PalletTypeEnum.Empty.ObjToInt() ? LocationStatusEnum.Pallet.ObjToInt() : LocationStatusEnum.InStock.ObjToInt(); _locationInfoService.Repository.UpdateData(targetLocationInfo); // 5.2 åè´§ä½éæ¾ç©ºé² int beforeOldLocationStatus = 0; if (oldLocationInfo != null) { beforeOldLocationStatus = oldLocationInfo.LocationStatus; oldLocationInfo.LocationStatus = LocationStatusEnum.Free.ObjToInt(); _locationInfoService.Repository.UpdateData(oldLocationInfo); } // 5.3 æ´æ°åºåï¼ç»å®æ°è´§ä½ + æ¢å¤æ£å¸¸ç¶æ string oldLocationCode = stockInfo.LocationCode; stockInfo.LocationCode = targetLocationInfo.LocationCode; stockInfo.StockStatus = StockStatusEmun.å ¥åºå®æ.ObjToInt(); stockInfo.LocationType = targetLocationInfo.LocationType; _stockRepository.UpdateData(stockInfo); // 5.4 任塿 è®°ä¸ºå®æ task.TaskStatus = TaskStatusEnum.Finish.ObjToInt(); var result = _task_HtyService.DeleteAndMoveIntoHty(task, OperateTypeEnum.èªå¨å®æ); // æäº¤äºå¡ _unitOfWorkManage.CommitTran(); // ä»»å¡å½æ¡£å¤±è´¥åå é¤ if (!result) { await Db.Deleteable(task).ExecuteCommandAsync(); } // è®°å½è´§ä½ç¶æåæ´æ¥å¿ try { _locationStatusChangeRecordService.AddLocationStatusChangeRecord( targetLocationInfo, beforeTargetLocationStatus, StockChangeType.Inbound.ObjToInt(), $"è·¨åºåç§»åºå ¥åºï¼åè´§ä½ï¼{oldLocationCode}ï¼", task.TaskNum); if (oldLocationInfo != null) { _locationStatusChangeRecordService.AddLocationStatusChangeRecord( oldLocationInfo, beforeOldLocationStatus, StockChangeType.Outbound.ObjToInt(), $"è·¨åºåç§»åºåºåºï¼ç®æ è´§ä½ï¼{targetLocationInfo.LocationCode}ï¼", task.TaskNum); } } catch (Exception ex) { _logger.LogInformation($"CrossAreaRelocationTaskCompleted è®°å½æ¥å¿å¼å¸¸ï¼{ex.Message}"); } return content.OK("è·¨åºåç§»åºä»»å¡å®æ"); } catch (Exception ex) { _unitOfWorkManage.RollbackTran(); _logger.LogError($"CrossAreaRelocationTaskCompleted å¤ç失败ï¼{ex.Message}", ex); return await Task.FromResult(WebResponseContent.Instance.Error($"è·¨åºåç§»åºä»»å¡å¤ç失败ï¼{ex.Message}")); } } } } ÏîÄ¿´úÂë/WMSÎÞ²Ö´¢°æ/WIDESEA_WMSServer/WIDESEA_TaskInfoService/TaskService_Outbound.cs
@@ -1441,6 +1441,149 @@ } } } /// <summary> /// éå®åºåè·¨åºåç§»åº /// </summary> /// <param name="stockViews"></param> /// <param name="targetLocationType">ç®æ è´§ä½ç±»å</param> /// <returns></returns> public async Task<WebResponseContent> CrossAreaOutbound(List<StockViewDTO> stockViews, int targetLocationType) { WebResponseContent content = new WebResponseContent(); try { if(targetLocationType == (int)LocationTypeEnum.Electronic) { return content.Error("çµåä»ä¸å 许跨åºåç§»åº"); } List<int> ids = stockViews.Select(x => x.StockId).ToList(); List<Dt_StockInfo> stockInfos = _stockRepository.Db.Queryable<Dt_StockInfo>().Where(x => ids.Contains(x.Id)).Includes(x => x.Details).ToList(); if (stockInfos.Count != stockViews.Count) { StockViewDTO? stockViewDTO = stockViews.FirstOrDefault(x => !stockInfos.Select(x => x.PalletCode).Contains(x.PalletCode)); return content.Error($"æªæ¾å°{stockViewDTO?.PalletCode}åºå"); } List<string> locStrs = stockInfos.Select(x => x.LocationCode).ToList(); List<Dt_LocationInfo> locationInfos = _locationInfoService.Db.Queryable<Dt_LocationInfo>().Where(x => locStrs.Contains(x.LocationCode)).ToList(); if (stockInfos.Count != locationInfos.Count) { string? locStr = locStrs.FirstOrDefault(x => !locationInfos.Select(x => x.LocationCode).Contains(x)); return content.Error($"æªæ¾å°{locStr}è´§ä½æ°æ®"); } foreach (var item in stockInfos) { if (item.PalletType != PalletTypeEnum.Empty.ObjToInt()) { return content.Error($"æçã{item.PalletCode}ãé空箱ï¼ä» 空箱å 许跨åºåç§»åºï¼"); } Dt_LocationInfo? locationInfo = locationInfos.FirstOrDefault(x => x.LocationCode == item.LocationCode); if (locationInfo == null || locationInfo.EnableStatus != EnableStatusEnum.Normal.ObjToInt() || item.StockStatus != StockStatusEmun.å ¥åºå®æ.ObjToInt()) { return content.Error($"{item.PalletCode}è´§ä½æåºåç¶æä¸æ»¡è¶³åºåºæ¡ä»¶"); } } List<Dt_Task> tasks = CrossAreaGetTasks(stockInfos, targetLocationType, TaskTypeEnum.CrossAreaRelocation); if (tasks == null || tasks.Count <= 0) { return content.Error("çæè·¨åºåç§»åºä»»å¡å¤±è´¥"); } stockInfos.ForEach(x => { x.StockStatus = StockStatusEmun.åºåºéå®.ObjToInt(); }); tasks.ForEach(x => { x.OrderNo = "è·¨åºåç§»åº"; }); locationInfos.ForEach(x => { x.LocationStatus = LocationStatusEnum.Lock.ObjToInt(); }); _unitOfWorkManage.BeginTran(); _stockRepository.UpdateData(stockInfos); BaseDal.AddData(tasks); _locationInfoService.UpdateData(locationInfos); _unitOfWorkManage.CommitTran(); content.OK(); } catch (Exception ex) { _unitOfWorkManage.RollbackTran(); return await Task.FromResult(WebResponseContent.Instance.Error(ex.Message)); } return content; } /// <summary> /// çæè·¨åºåç§»åºä»»å¡ /// </summary> /// <param name="stockInfos">åºåå表</param> /// <param name="targetAreaCode">ç®æ åºåç¼ç </param> /// <param name="taskType">ä»»å¡ç±»å</param> /// <returns></returns> public List<Dt_Task> CrossAreaGetTasks(List<Dt_StockInfo> stockInfos, int targetLocationType, TaskTypeEnum taskType) { using (var scope = new TransactionScope(TransactionScopeOption.Required, new TransactionOptions { IsolationLevel = IsolationLevel.ReadCommitted })) { try { List<Dt_Task> tasks = new List<Dt_Task>(); foreach (var stockInfo in stockInfos) { Dt_LocationInfo newLocation = _locationInfoService.AssignLocation(targetLocationType); if (newLocation == null) { throw new Exception($"{stockInfo.PalletCode} 没æç©ºé²è´§ä½å¯è¿è¡è·¨åºåç§»åº"); } if (!tasks.Exists(x => x.PalletCode == stockInfo.PalletCode)) { Dt_Task task = new() { CurrentAddress = stockInfo.LocationCode, Grade = 0, PalletCode = stockInfo.PalletCode, NextAddress = "", Roadway = newLocation.RoadwayNo, SourceAddress = stockInfo.LocationCode, TargetAddress = newLocation.LocationCode, TaskStatus = TaskStatusEnum.New.ObjToInt(), TaskType = taskType.ObjToInt(), PalletType = stockInfo.PalletType, WarehouseId = stockInfo.WarehouseId, }; tasks.Add(task); } newLocation.LocationStatus = LocationStatusEnum.Lock.ObjToInt(); _locationInfoService.UpdateData(newLocation); } scope.Complete(); return tasks; } catch (Exception ex) { throw new Exception(ex.Message); } } } } } ÏîÄ¿´úÂë/WMSÎÞ²Ö´¢°æ/WIDESEA_WMSServer/WIDESEA_WMSServer/Controllers/TaskInfo/TaskController.cs
@@ -144,5 +144,12 @@ { return await Service.AreaOutbound(stockViews); } [HttpPost, HttpGet, Route("CrossAreaOutbound"), AllowAnonymous] public async Task<WebResponseContent> CrossAreaOutbound([FromBody] List<StockViewDTO> stockViews,int targetLocationType) { return await Service.CrossAreaOutbound(stockViews,targetLocationType); } } }