diff --git a/ant-design-vue-jeecg/src/views/system/shipment/ShipmentHeaderList.vue b/ant-design-vue-jeecg/src/views/system/shipment/ShipmentHeaderList.vue index de8831e..dc976ae 100644 --- a/ant-design-vue-jeecg/src/views/system/shipment/ShipmentHeaderList.vue +++ b/ant-design-vue-jeecg/src/views/system/shipment/ShipmentHeaderList.vue @@ -105,9 +105,9 @@ <!-- 操作按钮区域 --> <div class="table-operator"> <a-button v-has="'shipmentHeader:add'" @click="handleAdd" type="primary" icon="plus">新增</a-button> + <a-button @click="mergeShipment" type="primary" v-has="'shipmentHeader:autoShipmentCombine'">合并单据</a-button> <a-button v-has="'shipmentHeader:export'" type="primary" icon="download" @click="handleExportXls('出库单')">导出</a-button> - <a-upload v-has="'shipmentHeader:import'" name="file" :showUploadList="false" :multiple="false" :headers="tokenHeader" :action="importExcelUrl" - @change="handleImportExcel"> + <a-upload v-has="'shipmentHeader:import'" name="file" :showUploadList="false" :multiple="false" :headers="tokenHeader" :action="importExcelUrl" @change="handleImportExcel"> <a-button type="primary" icon="import">导入</a-button> <a-button v-has="'shipmentHeader:print'" @click="batchPrint()" type="primary">打印</a-button> </a-upload> @@ -135,7 +135,7 @@ :dataSource="dataSource" :pagination="ipagination" :loading="loading" - :rowSelection="{selectedRowKeys: selectedRowKeys, onChange: onSelectChange, type:'radio'}" + :rowSelection="{selectedRowKeys: selectedRowKeys, onChange: onSelectChange, type:'checkbox'}" :customRow="clickThenSelect" @change="handleTableChange"> @@ -400,6 +400,25 @@ export default { } }, methods: { + mergeShipment() { + debugger + if (this.selectedRowKeys.length <= 1) { + this.$message.warning('至少选择两条记录!') + return + } + var shipmentHeaderList = [] + for (var a = 0; a < this.selectedRowKeys.length; a++) { + if (this.selectionRows[a] != null && this.selectionRows[a].firstStatus == 0 && this.selectionRows[a].lastStatus == 0) { + shipmentHeaderList.push(this.selectionRows[a]) + } + } + if (shipmentHeaderList.length > 0) { + this.$refs.modalForm2.batchEdit(shipmentHeaderList) + this.$refs.modalForm2.title = '选择出库口' + } else { + this.$message.error("至少选择两条符合条件的记录!") + } + }, getDocumentAduitFlowStaus(){ getDocumentAduitFlow().then((res) => { this.flowOff=res.message; @@ -435,7 +454,9 @@ export default { this.selectedMainId = '' }, onSelectChange(selectedRowKeys, selectionRows) { - this.selectedMainId = selectedRowKeys[0].toString(); + if (selectedRowKeys.length > 0) { + this.selectedMainId = selectedRowKeys[0].toString(); + } this.selectedRowKeys = selectedRowKeys; this.selectionRows = selectionRows; this.flowStatus = selectionRows[0].firstStatus.toString(); diff --git a/huaheng-wms-core/src/main/java/org/jeecg/modules/wms/framework/controller/HuahengBaseController.java b/huaheng-wms-core/src/main/java/org/jeecg/modules/wms/framework/controller/HuahengBaseController.java index 6279bfe..bdea89d 100644 --- a/huaheng-wms-core/src/main/java/org/jeecg/modules/wms/framework/controller/HuahengBaseController.java +++ b/huaheng-wms-core/src/main/java/org/jeecg/modules/wms/framework/controller/HuahengBaseController.java @@ -6,6 +6,7 @@ import javax.annotation.Nonnull; import org.jeecg.common.api.vo.Result; import org.jeecg.common.exception.JeecgBootException; +import org.jeecg.modules.wms.task.taskHeader.entity.TaskHeader; import org.jeecg.utils.support.RedissonDistributedLocker; import org.springframework.beans.factory.annotation.Autowired; @@ -59,14 +60,29 @@ public class HuahengBaseController { * @return */ public Result<?> handleMultiProcess(@Nonnull String taskName, @Nonnull String lockKey, MultiProcessListener multiProcessListener) { + return this.handleMultiProcess(taskName, lockKey, WAIT_TIME, LEASE_TIME, multiProcessListener); + } + + /** + * 获取分布式锁,自定义锁等待,释放时间</br> + * 注意锁与事务的顺序:获取分布式锁 -> 开启事务 -> 执行业务 -> 提交事务 -> 释放分布式锁 + * @author TanYibin + * @createDate 2023年2月8日 + * @param taskName + * @param lockKey + * @param multiProcessListener + * @return + */ + public Result<?> handleMultiProcess(@Nonnull String taskName, @Nonnull String lockKey, @Nonnull Integer waitTime, @Nonnull Integer leaseTime, + MultiProcessListener multiProcessListener) { Result<?> result = null; final long startTime = SystemClock.now(); final String fullLockKey = "RedissonLock_" + taskName + "_" + lockKey; - final boolean tryLock = redissonDistributedLocker.tryLock(fullLockKey, TimeUnit.SECONDS, WAIT_TIME, LEASE_TIME); + final boolean tryLock = redissonDistributedLocker.tryLock(fullLockKey, TimeUnit.SECONDS, waitTime, leaseTime); final long endTime = SystemClock.now(); if (!tryLock) { log.error("[{}] 获取分布式锁失败 lockKey = {},等待锁耗时:{}ms", taskName, fullLockKey, endTime - startTime); - throw new RuntimeException(StrUtil.format("[{}] 获取分布式锁失败 lockKey = {},等待时间超出10秒", taskName, fullLockKey)); + throw new RuntimeException(StrUtil.format("[{}] 获取分布式锁失败 lockKey = {},超出设定等待时间:{}s", taskName, fullLockKey, waitTime)); } // 注意:一定是获取锁成功后,才进行try{}finally{释放锁} try { diff --git a/huaheng-wms-core/src/main/java/org/jeecg/modules/wms/framework/service/IHuahengMultiHandlerService.java b/huaheng-wms-core/src/main/java/org/jeecg/modules/wms/framework/service/IHuahengMultiHandlerService.java index 4f5f02e..bf56550 100644 --- a/huaheng-wms-core/src/main/java/org/jeecg/modules/wms/framework/service/IHuahengMultiHandlerService.java +++ b/huaheng-wms-core/src/main/java/org/jeecg/modules/wms/framework/service/IHuahengMultiHandlerService.java @@ -1,5 +1,7 @@ package org.jeecg.modules.wms.framework.service; +import java.util.List; + import org.jeecg.common.api.vo.Result; import org.jeecg.modules.wms.api.mobile.entity.CallBoxBean; import org.jeecg.modules.wms.api.mobile.entity.QuickReceiptBean; @@ -16,8 +18,6 @@ import org.jeecg.modules.wms.task.taskHeader.entity.TaskHeader; */ public interface IHuahengMultiHandlerService { - Result sendTaskToWcs(TaskHeader taskHeader); - Result createReceiptTask(ReceiptContainerHeader receiptContainerHeader, String warehouseCode); Result combination(CombinationModel combinationModel); @@ -45,4 +45,9 @@ public interface IHuahengMultiHandlerService { Result backReceipt(ReceiptHeader receiptHeader); Result backShipment(ShipmentHeader shipmentHeader); + + Result sendTaskToWcs(TaskHeader taskHeader, String zoneCode); + + void sendTaskToWcs(List<TaskHeader> taskHeaders, String warehouseCode, String zoneCode); + } diff --git a/huaheng-wms-core/src/main/java/org/jeecg/modules/wms/framework/service/impl/HuahengMultiHandlerServiceImpl.java b/huaheng-wms-core/src/main/java/org/jeecg/modules/wms/framework/service/impl/HuahengMultiHandlerServiceImpl.java index e97ac9b..44009fb 100644 --- a/huaheng-wms-core/src/main/java/org/jeecg/modules/wms/framework/service/impl/HuahengMultiHandlerServiceImpl.java +++ b/huaheng-wms-core/src/main/java/org/jeecg/modules/wms/framework/service/impl/HuahengMultiHandlerServiceImpl.java @@ -1,6 +1,7 @@ package org.jeecg.modules.wms.framework.service.impl; import java.math.BigDecimal; +import java.util.List; import javax.annotation.Resource; @@ -26,11 +27,15 @@ import org.jeecg.modules.wms.shipment.shipmentHeader.entity.ShipmentHeader; import org.jeecg.modules.wms.shipment.shipmentHeader.service.IShipmentDetailService; import org.jeecg.modules.wms.task.taskHeader.entity.TaskHeader; import org.jeecg.modules.wms.task.taskHeader.service.ITaskHeaderService; +import org.springframework.scheduling.annotation.Async; import org.springframework.stereotype.Service; +import lombok.extern.slf4j.Slf4j; + /** * @author 游杰 */ +@Slf4j @Service public class HuahengMultiHandlerServiceImpl extends HuahengBaseController implements IHuahengMultiHandlerService { @@ -59,21 +64,41 @@ public class HuahengMultiHandlerServiceImpl extends HuahengBaseController implem private IErpService erpService; @Override - public Result sendTaskToWcs(TaskHeader taskHeader) { + public Result sendTaskToWcs(TaskHeader taskHeader, String zoneCode) { if (taskHeader == null) { return Result.error("任务信息为空"); } - String lockKey = taskHeader.getWarehouseCode(); - Result result = handleMultiProcess("sendTaskToWcs", lockKey, new MultiProcessListener() { + String lockKey = taskHeader.getWarehouseCode() + "_" + zoneCode; + Result result = handleMultiProcess("sendTaskToWcs", lockKey, 10, 300, new MultiProcessListener() { + @Override public Result<?> doProcess() { - Result result = taskHeaderService.sendTaskToWcs(taskHeader.getId()); - return result; + return taskHeaderService.sendTaskToWcs(taskHeader.getId()); } }); return result; } + @Async("baseExecutor") + @Override + public void sendTaskToWcs(List<TaskHeader> taskHeaders, String warehouseCode, String zoneCode) { + String lockKey = warehouseCode + "_" + zoneCode; + handleMultiProcess("sendTaskToWcs", lockKey, 10, 300, new MultiProcessListener() { + + @Override + public Result<?> doProcess() { + for (TaskHeader taskHeader : taskHeaders) { + try { + taskHeaderService.sendTaskToWcs(taskHeader.getId()); + } catch (Exception e) { + log.error("sendTaskToWcs 执行异常,errorMessage: {}", e.getMessage(), e); + } + } + return Result.OK(); + } + }); + } + @Override public Result createReceiptTask(ReceiptContainerHeader receiptContainerHeader, String warehouseCode) { Result result = handleMultiProcess("createReceiptTask", warehouseCode, new MultiProcessListener() { diff --git a/huaheng-wms-core/src/main/java/org/jeecg/modules/wms/monitor/job/WcsTask.java b/huaheng-wms-core/src/main/java/org/jeecg/modules/wms/monitor/job/WcsTask.java index cf395e7..80a419e 100644 --- a/huaheng-wms-core/src/main/java/org/jeecg/modules/wms/monitor/job/WcsTask.java +++ b/huaheng-wms-core/src/main/java/org/jeecg/modules/wms/monitor/job/WcsTask.java @@ -1,13 +1,15 @@ package org.jeecg.modules.wms.monitor.job; -import java.util.HashMap; +import java.util.Date; import java.util.List; import java.util.Map; +import java.util.stream.Collectors; import javax.annotation.Resource; -import org.apache.commons.collections.MapUtils; import org.jeecg.common.util.DateUtils; +import org.jeecg.modules.wms.config.container.entity.Container; +import org.jeecg.modules.wms.config.container.service.IContainerService; import org.jeecg.modules.wms.framework.service.IHuahengMultiHandlerService; import org.jeecg.modules.wms.task.taskHeader.entity.TaskHeader; import org.jeecg.modules.wms.task.taskHeader.service.ITaskHeaderService; @@ -17,10 +19,13 @@ import org.quartz.Job; import org.quartz.JobExecutionContext; import org.quartz.JobExecutionException; import org.quartz.PersistJobDataAfterExecution; +import org.springframework.util.CollectionUtils; +import org.springframework.util.StringUtils; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import cn.hutool.core.date.DateUtil; import lombok.extern.slf4j.Slf4j; /** @@ -39,18 +44,29 @@ public class WcsTask implements Job { @Resource private IHuahengMultiHandlerService huahengMultiHandlerService; + @Resource + private IContainerService containerService; + @Override public void execute(JobExecutionContext context) throws JobExecutionException { log.info(String.format(" WcsTask 执行任务! 时间:" + DateUtils.getTimestamp())); LambdaQueryWrapper<TaskHeader> taskHeaderLambdaQueryWrapper = Wrappers.lambdaQuery(); - taskHeaderLambdaQueryWrapper.eq(TaskHeader::getStatus, QuantityConstant.TASK_STATUS_BUILD).eq(TaskHeader::getAgvTaskId, 0); + taskHeaderLambdaQueryWrapper.eq(TaskHeader::getStatus, QuantityConstant.TASK_STATUS_BUILD).eq(TaskHeader::getAgvTaskId, 0) + .ge(TaskHeader::getCreateTime, DateUtil.offsetDay(new Date(), -180)).orderByAsc(TaskHeader::getCreateTime); List<TaskHeader> taskHeaderList = taskHeaderService.list(taskHeaderLambdaQueryWrapper); - for (TaskHeader taskHeader : taskHeaderList) { - try { - huahengMultiHandlerService.sendTaskToWcs(taskHeader); - } catch (Exception e) { - e.printStackTrace(); - } + if (CollectionUtils.isEmpty(taskHeaderList)) { + return; } + LambdaQueryWrapper<Container> containerLambdaQueryWrapper = Wrappers.lambdaQuery(); + containerLambdaQueryWrapper.in(Container::getCode, taskHeaderList.stream().map(TaskHeader::getContainerCode).collect(Collectors.toList())); + List<Container> containerList = containerService.list(containerLambdaQueryWrapper); + Map<String, String> containerZoneCodeMap = containerList.stream().collect(Collectors.toMap(Container::getCode, Container::getZoneCode)); + Map<String, List<TaskHeader>> groupeTaskHeaders = + taskHeaderList.stream().collect(Collectors.groupingBy(taskHeader -> StringUtils.isEmpty(containerZoneCodeMap.get(taskHeader.getContainerCode())) + ? QuantityConstant.DEFAULT_ZONE_CODE : containerZoneCodeMap.get(taskHeader.getContainerCode()))); + // 循环 groupedTaskHeaders 中的每个键值对 + groupeTaskHeaders.forEach((zoneCode, taskHeaders) -> { + huahengMultiHandlerService.sendTaskToWcs(taskHeaders, taskHeaders.get(0).getWarehouseCode(), zoneCode); + }); } } diff --git a/huaheng-wms-core/src/main/java/org/jeecg/modules/wms/task/taskHeader/controller/TaskHeaderController.java b/huaheng-wms-core/src/main/java/org/jeecg/modules/wms/task/taskHeader/controller/TaskHeaderController.java index 8c91b7f..3b2eef3 100644 --- a/huaheng-wms-core/src/main/java/org/jeecg/modules/wms/task/taskHeader/controller/TaskHeaderController.java +++ b/huaheng-wms-core/src/main/java/org/jeecg/modules/wms/task/taskHeader/controller/TaskHeaderController.java @@ -387,8 +387,8 @@ public class TaskHeaderController extends HuahengBaseController { if (taskHeader == null) { return Result.error("taskHeader不能为空"); } - Result result = huahengMultiHandlerService.sendTaskToWcs(taskHeader); - return result; + Container container = containerService.getContainerByCode(taskHeader.getContainerCode(), taskHeader.getWarehouseCode()); + return huahengMultiHandlerService.sendTaskToWcs(taskHeader, container == null ? QuantityConstant.DEFAULT_ZONE_CODE : container.getZoneCode()); } /** diff --git a/huaheng-wms-core/src/main/java/org/jeecg/utils/constant/QuantityConstant.java b/huaheng-wms-core/src/main/java/org/jeecg/utils/constant/QuantityConstant.java index a42c088..279d686 100644 --- a/huaheng-wms-core/src/main/java/org/jeecg/utils/constant/QuantityConstant.java +++ b/huaheng-wms-core/src/main/java/org/jeecg/utils/constant/QuantityConstant.java @@ -616,4 +616,7 @@ public class QuantityConstant { * 受控,受控的库存详情不能出库 */ public static final int CONTROLLER_ENABLE = 1; + + /** 默认库区编码 */ + public static final String DEFAULT_ZONE_CODE = "Default"; }