src/main/java/com/zy/asrs/service/impl/OpenServiceImpl.java
@@ -76,8 +76,14 @@ // 根据taskId查询任务 Task task = null; try { // 处理"T"前缀格式(如"T130"),这是AGV任务创建时的格式 String numericId = taskId; if (taskId.startsWith("T") && taskId.length() > 1) { numericId = taskId.substring(1); log.debug("检测到T前缀格式的taskId,提取数字ID:{}", numericId); } // 尝试将taskId解析为Long类型的id Long taskIdLong = Long.parseLong(taskId); Long taskIdLong = Long.parseLong(numericId); task = taskService.selectById(taskIdLong); } catch (NumberFormatException e) { // 如果不是数字,尝试通过其他字段查询(如sheetNo等) @@ -131,8 +137,16 @@ String kind = param.getKind(); if ("货物转运".equals(kind)) { log.info("处理货物转运任务,taskId:{}", taskId); } else if ("实托入库".equals(kind)) { log.info("处理实托入库任务,taskId:{}", taskId); } else if ("实托入库".equals(kind) || "空托入库".equals(kind)) { log.info("处理入库任务,taskId:{}", taskId); // 入库任务:如果收到确认取货回调(loaded=true),完结AGV呼叫单 if (Boolean.TRUE.equals(param.getLoaded())) { // 如果任务状态是8(已呼叫AGV),更新为9(任务完成) if (task.getWrkSts() != null && task.getWrkSts() == 8L) { task.setWrkSts(9L); log.info("入库任务收到确认取货回调,完结AGV呼叫单,taskId:{}", taskId); } } } else if ("实托出库".equals(kind)) { log.info("处理实托出库任务,taskId:{}", taskId); } src/main/java/com/zy/asrs/task/AgvScheduler.java
@@ -1,21 +1,27 @@ package com.zy.asrs.task; import com.baomidou.mybatisplus.mapper.EntityWrapper; import com.baomidou.mybatisplus.mapper.Wrapper; import com.core.common.Cools; import com.zy.asrs.entity.Task; import com.zy.asrs.entity.WrkMast; import com.zy.asrs.mapper.WrkMastMapper; import com.zy.asrs.entity.WrkMastLog; import com.zy.asrs.service.TaskService; import com.zy.asrs.service.WrkMastLogService; import com.zy.asrs.service.WrkMastService; import com.zy.asrs.task.handler.AgvHandler; import com.zy.common.properties.SchedulerProperties; import com.zy.system.entity.Config; import com.zy.system.service.ConfigService; import org.springframework.scheduling.TaskScheduler; import lombok.extern.slf4j.Slf4j; import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Component; import javax.annotation.Resource; import java.util.ArrayList; import java.util.Arrays; import java.util.Date; import java.util.List; /** @@ -23,6 +29,7 @@ * @description AGV交互相关定时任务 * @createDate 2025/11/18 14:18 */ @Slf4j @Component public class AgvScheduler { @@ -38,13 +45,29 @@ @Resource private WrkMastMapper wrkMastMapper; @Resource private WrkMastService wrkMastService; @Resource private WrkMastLogService wrkMastLogService; @Resource private SchedulerProperties schedulerProperties; /** * 呼叫agv搬运 */ @Scheduled(cron = "0/5 * * * * ? ") private void callAgv() { // 查询待呼叫agv任务 List<Task> taskList = taskService.selectList(new EntityWrapper<Task>().eq("wrk_sts", 7)); if (!schedulerProperties.isEnabled()) { return; } // 查询待呼叫agv任务,按id升序排序(id最小的优先呼叫) List<Task> taskList = taskService.selectList( new EntityWrapper<Task>() .eq("wrk_sts", 7) .orderBy("id", true) // 按id升序,id最小的优先 ); if(taskList.isEmpty()) { return; } @@ -56,6 +79,9 @@ */ @Scheduled(cron = "0/3 * * * * ? ") private void createAgvOutTasks() { if (!schedulerProperties.isEnabled()) { return; } // 获取呼叫agv配置 List<Config> configs = configService.selectList(new EntityWrapper<Config>().in("code", "eastCallAgvControl", "westCallAgvControl").eq("status", 1)); @@ -86,6 +112,9 @@ */ @Scheduled(cron = "0/10 * * * * ? ") private void moveTaskToHistory() { if (!schedulerProperties.isEnabled()) { return; } List<Task> taskList = taskService.selectList(new EntityWrapper<Task>().eq("wrk_sts", 9)); if(taskList.isEmpty()) { return; @@ -93,5 +122,191 @@ agvHandler.moveTaskToHistory(taskList); } /** * 检查入库成功的任务,完结对应的AGV呼叫单 * 如果入库任务呼叫AGV后没有收到回调,但工作档已经入库成功,则完结AGV呼叫单 */ @Scheduled(cron = "0/10 * * * * ? ") private void checkInboundCompletedTasks() { if (!schedulerProperties.isEnabled()) { return; } try { // 查询入库成功的工作档(状态4:入库完成,入库类型:1,10,53,57) List<WrkMast> completedWrkMasts = wrkMastService.selectList( new EntityWrapper<WrkMast>() .eq("wrk_sts", 4L) // 入库完成 .in("io_type", 1, 10, 53, 57) // 入库类型 .isNotNull("wrk_no") ); if (completedWrkMasts.isEmpty()) { return; } Date now = new Date(); int completedCount = 0; for (WrkMast wrkMast : completedWrkMasts) { // 查找对应的AGV任务(优先通过wrk_no查询) Wrapper<Task> taskWrapper1 = new EntityWrapper<Task>() .eq("task_type", "agv") .eq("wrk_sts", 8L) // 已呼叫AGV状态 .eq("wrk_no", wrkMast.getWrkNo()); List<Task> agvTasks = taskService.selectList(taskWrapper1); // 如果通过wrk_no没找到,且有条码,则通过条码查询 if (agvTasks.isEmpty() && !Cools.isEmpty(wrkMast.getBarcode())) { Wrapper<Task> taskWrapper2 = new EntityWrapper<Task>() .eq("task_type", "agv") .eq("wrk_sts", 8L) .eq("barcode", wrkMast.getBarcode()); agvTasks = taskService.selectList(taskWrapper2); } for (Task agvTask : agvTasks) { // 确保是入库任务 if (agvTask.getIoType() != null && (agvTask.getIoType() == 1 || agvTask.getIoType() == 10 || agvTask.getIoType() == 53 || agvTask.getIoType() == 57)) { // 更新AGV任务状态为完成 agvTask.setWrkSts(9L); agvTask.setModiTime(now); if (taskService.updateById(agvTask)) { completedCount++; log.info("入库任务工作档已入库成功,完结AGV呼叫单,taskId:{},wrkNo:{},barcode:{}", agvTask.getId(), wrkMast.getWrkNo(), wrkMast.getBarcode()); } } } } if (completedCount > 0) { log.info("本次检查完结了{}个入库AGV呼叫单", completedCount); } } catch (Exception e) { log.error("检查入库成功任务并完结AGV呼叫单异常", e); } } /** * 检查AGV任务对应的工作档是否已完成或已转历史档并完结 * 处理被跳过的AGV任务:如果工作档已完成(wrk_sts=4,5,14,15)或已转历史档并完结,则完结AGV任务 */ @Scheduled(cron = "0/10 * * * * ? ") private void checkCompletedTasksInHistory() { if (!schedulerProperties.isEnabled()) { return; } try { // 查询状态为8(已呼叫AGV)的AGV任务 List<Task> agvTasks = taskService.selectList( new EntityWrapper<Task>() .eq("task_type", "agv") .eq("wrk_sts", 8L) // 已呼叫AGV状态 .isNotNull("wrk_no") ); if (agvTasks.isEmpty()) { return; } Date now = new Date(); int completedCount = 0; for (Task agvTask : agvTasks) { boolean isCompleted = false; String reason = ""; // 检查工作档是否存在 WrkMast wrkMast = null; if (agvTask.getWrkNo() != null) { wrkMast = wrkMastService.selectOne( new EntityWrapper<WrkMast>().eq("wrk_no", agvTask.getWrkNo()) ); } // 如果工作档存在,检查是否已完成 if (wrkMast != null) { Long wrkSts = wrkMast.getWrkSts(); Integer ioType = agvTask.getIoType(); if (wrkSts != null && ioType != null) { // 入库任务:状态4(入库完成)或5(库存更新完成) if ((ioType == 1 || ioType == 10 || ioType == 53 || ioType == 57) && (wrkSts == 4L || wrkSts == 5L)) { isCompleted = true; reason = String.format("工作档已完成,状态:%d", wrkSts); } // 出库任务:状态14(已出库未确认)或15(出库更新完成) else if ((ioType == 101 || ioType == 110 || ioType == 103 || ioType == 107) && (wrkSts == 14L || wrkSts == 15L)) { isCompleted = true; reason = String.format("工作档已完成,状态:%d", wrkSts); } } } else { // 如果工作档不存在,检查历史档 WrkMastLog wrkMastLog = null; // 优先通过wrk_no查询历史档 if (agvTask.getWrkNo() != null) { wrkMastLog = wrkMastLogService.selectOne( new EntityWrapper<WrkMastLog>().eq("wrk_no", agvTask.getWrkNo()) ); } // 如果通过wrk_no没找到,且有条码,则通过条码查询 if (wrkMastLog == null && !Cools.isEmpty(agvTask.getBarcode())) { List<WrkMastLog> logList = wrkMastLogService.selectList( new EntityWrapper<WrkMastLog>().eq("barcode", agvTask.getBarcode()) ); if (!logList.isEmpty()) { wrkMastLog = logList.get(0); // 取第一个 } } // 如果历史档存在且已完结,则完结AGV任务 if (wrkMastLog != null) { Integer ioType = agvTask.getIoType(); long logWrkSts = wrkMastLog.getWrkSts(); if (ioType != null) { // 入库任务:状态5(库存更新完成) if ((ioType == 1 || ioType == 10 || ioType == 53 || ioType == 57) && logWrkSts == 5L) { isCompleted = true; reason = String.format("工作档已转历史档并完结,历史档状态:%d", logWrkSts); } // 出库任务:状态15(出库更新完成) else if ((ioType == 101 || ioType == 110 || ioType == 103 || ioType == 107) && logWrkSts == 15L) { isCompleted = true; reason = String.format("工作档已转历史档并完结,历史档状态:%d", logWrkSts); } } } } // 如果已完成,更新AGV任务状态 if (isCompleted) { agvTask.setWrkSts(9L); agvTask.setModiTime(now); if (taskService.updateById(agvTask)) { completedCount++; log.info("{},完结AGV呼叫单,taskId:{},wrkNo:{},barcode:{},站点:{}", reason, agvTask.getId(), agvTask.getWrkNo(), agvTask.getBarcode(), agvTask.getStaNo()); } } } if (completedCount > 0) { log.info("本次检查完结了{}个AGV呼叫单(工作档已完成或已转历史档)", completedCount); } } catch (Exception e) { log.error("检查工作档已完成或历史档完结任务并完结AGV呼叫单异常", e); } } } src/main/java/com/zy/asrs/task/ErrorStockScheduler.java
@@ -2,11 +2,14 @@ import com.zy.asrs.task.core.ReturnT; import com.zy.asrs.task.handler.ErrorStockHandler; import com.zy.common.properties.SchedulerProperties; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Component; import javax.annotation.Resource; /** * Created by vincent on 2020/7/7 @@ -19,8 +22,14 @@ @Autowired private ErrorStockHandler errorStockHandler; @Resource private SchedulerProperties schedulerProperties; @Scheduled(cron = "0/3 * * * * ? ") private void execute() { if (!schedulerProperties.isEnabled()) { return; } ReturnT<String> returnT = errorStockHandler.start(); if (!returnT.isSuccess()) { log.error(returnT.getMsg()); src/main/java/com/zy/asrs/task/InventoryReserveScheduler.java
@@ -2,10 +2,13 @@ import com.zy.asrs.task.core.ReturnT; import com.zy.asrs.task.handler.InventoryReserveExpireHandler; import com.zy.common.properties.SchedulerProperties; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Component; import javax.annotation.Resource; /** * 预留库存过期定时任务调度器 @@ -18,11 +21,17 @@ @Autowired private InventoryReserveExpireHandler inventoryReserveExpireHandler; @Resource private SchedulerProperties schedulerProperties; /** * 每分钟执行一次,检查过期的预留库存 */ @Scheduled(cron = "0 * * * * ?") public void checkExpiredReserve() { if (!schedulerProperties.isEnabled()) { return; } try { ReturnT<String> result = inventoryReserveExpireHandler.start(); if (!result.isSuccess()) { src/main/java/com/zy/asrs/task/NotifyLogScheduler.java
@@ -2,11 +2,14 @@ import com.zy.asrs.task.core.ReturnT; import com.zy.asrs.task.handler.NotifyLogHandler; import com.zy.common.properties.SchedulerProperties; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Component; import javax.annotation.Resource; /** * Created by vincent on 2020/7/7 @@ -19,8 +22,14 @@ @Autowired private NotifyLogHandler notifyLogHandler; @Resource private SchedulerProperties schedulerProperties; @Scheduled(cron = "0/3 * * * * ? ") private void execute() { if (!schedulerProperties.isEnabled()) { return; } ReturnT<String> returnT = notifyLogHandler.start(); if (!returnT.isSuccess()) { log.error(returnT.getMsg()); src/main/java/com/zy/asrs/task/OrderMoveHistoryScheduler.java
@@ -2,9 +2,12 @@ import com.zy.asrs.task.handler.OrderPakinMoveHistoryHandler; import com.zy.asrs.task.handler.OrderPakoutMoveHistoryHandler; import com.zy.common.properties.SchedulerProperties; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Component; import javax.annotation.Resource; @Component @@ -15,11 +18,17 @@ @Autowired private OrderPakoutMoveHistoryHandler orderPakoutMoveHistoryHandler; @Resource private SchedulerProperties schedulerProperties; /** * 将已完成order和orderDetl移动到log表 */ @Scheduled(cron = "0/30 * * * * ?") public void execute() { if (!schedulerProperties.isEnabled()) { return; } orderPakinMoveHistoryHandler.start(); } @@ -28,6 +37,9 @@ */ @Scheduled(cron = "0/30 * * * * ?") public void executeOrder() { if (!schedulerProperties.isEnabled()) { return; } orderPakoutMoveHistoryHandler.start(); } } src/main/java/com/zy/asrs/task/OrderSyncScheduler.java
@@ -8,6 +8,7 @@ import com.zy.asrs.task.core.ReturnT; import com.zy.asrs.task.handler.OrderPakinSyncHandler; import com.zy.asrs.task.handler.OrderPakoutSyncHandler; import com.zy.common.properties.SchedulerProperties; import com.zy.system.timer.LoadingConfigTimer; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; @@ -15,6 +16,7 @@ import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Component; import javax.annotation.Resource; import java.util.List; /** @@ -37,9 +39,15 @@ @Autowired private LoadingConfigTimer loadingConfigTimer; @Resource private SchedulerProperties schedulerProperties; @Scheduled(cron = "0/30 * * * * ? ") @Async("orderThreadPool") public void completeOrderPakin() { if (!schedulerProperties.isEnabled()) { return; } if (loadingConfigTimer.getErpReport()) { List<OrderPakin> orders = orderPakinService.selectComplete(); for (OrderPakin order : orders) { @@ -59,6 +67,9 @@ @Scheduled(cron = "0/30 * * * * ? ") @Async("orderThreadPool") public void completeOrderPakout() { if (!schedulerProperties.isEnabled()) { return; } if (loadingConfigTimer.getErpReport()) { List<OrderPakout> orders = orderPakoutService.selectComplete(); for (OrderPakout order : orders) { @@ -77,6 +88,9 @@ @Scheduled(cron = "0 0 1 * * ? ") public void clearApiLog() { if (!schedulerProperties.isEnabled()) { return; } try { apiLogService.clearWeekBefore(); } catch (Exception e) { src/main/java/com/zy/asrs/task/OverYearLogScheduler.java
@@ -2,11 +2,14 @@ import com.zy.asrs.task.core.ReturnT; import com.zy.asrs.task.handler.OverYearLogHandler; import com.zy.common.properties.SchedulerProperties; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Component; import javax.annotation.Resource; /** * Created by vincent on 2020/7/7 @@ -19,8 +22,14 @@ @Autowired private OverYearLogHandler overYearLogHandler; @Resource private SchedulerProperties schedulerProperties; @Scheduled(cron = "0 0 1 * * ? ") private void execute() { if (!schedulerProperties.isEnabled()) { return; } ReturnT<String> returnT = overYearLogHandler.start(); if (!returnT.isSuccess()) { log.error(returnT.getMsg()); src/main/java/com/zy/asrs/task/PlcLogScheduler.java
@@ -2,11 +2,14 @@ import com.zy.asrs.task.core.ReturnT; import com.zy.asrs.task.handler.PlcLogHandler; import com.zy.common.properties.SchedulerProperties; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Component; import javax.annotation.Resource; /** * Created by vincent on 2020/7/7 @@ -19,8 +22,14 @@ @Autowired private PlcLogHandler plcLogHandler; @Resource private SchedulerProperties schedulerProperties; @Scheduled(cron = "0/3 * * * * ? ") private void execute() { if (!schedulerProperties.isEnabled()) { return; } ReturnT<String> returnT = plcLogHandler.start(); if (!returnT.isSuccess()) { log.error(returnT.getMsg()); src/main/java/com/zy/asrs/task/WorkLogScheduler.java
@@ -6,11 +6,13 @@ import com.zy.asrs.service.WrkMastService; import com.zy.asrs.task.core.ReturnT; import com.zy.asrs.task.handler.WorkLogHandler; import com.zy.common.properties.SchedulerProperties; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Component; import javax.annotation.Resource; import java.util.List; /** @@ -29,9 +31,14 @@ @Autowired private TaskService taskService; @Resource private SchedulerProperties schedulerProperties; @Scheduled(cron = "0/3 * * * * ? ") private void execute() { if (!schedulerProperties.isEnabled()) { return; } List<WrkMast> wrkMasts = wrkMastService.selectToBeHistoryData(); if (wrkMasts.isEmpty()) { return; @@ -47,6 +54,9 @@ @Scheduled(cron = "0/3 * * * * ? ") private void executeTask(){ if (!schedulerProperties.isEnabled()) { return; } List<Task> taskList = taskService.selectToBeHistoryData(); if (taskList.isEmpty()) { return; src/main/java/com/zy/asrs/task/WorkMastScheduler.java
@@ -6,12 +6,14 @@ import com.zy.asrs.service.WrkMastService; import com.zy.asrs.task.core.ReturnT; import com.zy.asrs.task.handler.WorkMastHandler; import com.zy.common.properties.SchedulerProperties; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Component; import javax.annotation.Resource; import java.util.Date; import java.util.List; @@ -30,8 +32,14 @@ @Autowired private TaskService taskService; @Resource private SchedulerProperties schedulerProperties; @Scheduled(cron = "0/3 * * * * ? ") private void execute() { if (!schedulerProperties.isEnabled()) { return; } List<WrkMast> wrkMasts = wrkMastService.selectToBeCompleteData(); if (wrkMasts.isEmpty()) { return; @@ -51,6 +59,9 @@ @Scheduled(cron = "0/3 * * * * ? ") private void executeTask() { if (!schedulerProperties.isEnabled()) { return; } List<Task> wrkMasts = taskService.selectToBeCompleteData(); if (wrkMasts.isEmpty()) { return; src/main/java/com/zy/asrs/task/handler/AgvHandler.java
@@ -87,19 +87,38 @@ log.info("任务ID:{}已分配站点:{}", task.getId(), staNo); } // 检查目标站点是否有未完成的AGV任务 // 如果站点有未完成的任务,则跳过本次发送,等待下次 if (staNo != null && !staNo.isEmpty()) { List<Task> unfinishedTasks = taskService.selectList(new EntityWrapper<Task>() // 检查目标站点是否有正在搬运的同类型AGV任务(出库和入库互不干扰) // 只有状态8(已呼叫AGV,正在搬运)的任务才会阻塞,状态7(待呼叫)的任务不阻塞 // 这样可以避免所有任务都卡在呼叫状态,按id最小的优先呼叫 if (staNo != null && !staNo.isEmpty() && task.getIoType() != null) { // 根据当前任务类型,只检查同类型的正在搬运任务(状态8) // 入库任务(ioType < 100):只检查入库类型的正在搬运任务 // 出库任务(ioType >= 100):只检查出库类型的正在搬运任务 List<Integer> ioTypes; String taskType; if (task.getIoType() < 100) { // 入库任务:只检查入库类型(1, 10, 53, 57) ioTypes = Arrays.asList(1, 10, 53, 57); taskType = "入库"; } else { // 出库任务:只检查出库类型(101, 110, 103, 107) ioTypes = Arrays.asList(101, 110, 103, 107); taskType = "出库"; } // 只检查状态为8(已呼叫AGV,正在搬运)的同类型任务 List<Task> transportingTasks = taskService.selectList( new EntityWrapper<Task>() .eq("sta_no", staNo) .eq("task_type", "agv") .eq("wrk_sts", 8L) // 只检查正在搬运状态的任务 .in("io_type", ioTypes) .ne("id", task.getId()) // 排除当前任务本身 .last("AND wrk_sts NOT IN (5, 15)") // 排除已完成状态 ); if (!unfinishedTasks.isEmpty()) { log.info("站点{}有{}个未完成的AGV任务,跳过本次发送,等待任务完成。当前任务ID:{}", staNo, unfinishedTasks.size(), task.getId()); if (!transportingTasks.isEmpty()) { log.info("站点{}有{}个正在搬运的{}AGV任务,跳过本次发送,等待搬运完成。当前任务ID:{}", staNo, transportingTasks.size(), taskType, task.getId()); continue; // 跳过本次发送,等待下次 } } src/main/java/com/zy/asrs/task/handler/WorkMastHandler.java
@@ -9,6 +9,9 @@ import com.zy.asrs.service.impl.BasStationServiceImpl; import com.zy.asrs.task.AbstractHandler; import com.zy.asrs.task.core.ReturnT; import com.zy.common.model.enums.WorkNoType; import com.zy.common.properties.AgvProperties; import com.zy.common.service.CommonService; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.BeanUtils; import org.springframework.beans.factory.annotation.Autowired; @@ -16,6 +19,7 @@ import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.interceptor.TransactionAspectSupport; import java.util.Arrays; import java.util.Date; import java.util.List; import java.util.Objects; @@ -59,6 +63,12 @@ @Autowired private LocCacheDetlService locCacheDetlService; @Autowired private CommonService commonService; @Autowired private AgvProperties agvProperties; public ReturnT<String> start(WrkMast wrkMast) { // 4.入库完成 @@ -590,6 +600,9 @@ // 14.出库完成 } else if (task.getWrkSts() == 14) { return agvDoOut(task); // 15.出库更新完成 - 生成空托/满托出库任务 } else if (task.getWrkSts() == 15) { return generateEmptyOrFullPalletOutTaskForCompleted(task); } return SUCCESS; } @@ -636,6 +649,7 @@ if (!taskService.updateById(task)) { throw new CoolException("任务状态修改失败!!"); } // 注意:生成空托/满托出库任务的逻辑已移至状态15的处理方法中 } else if(task.getIoType().equals(53) || task.getIoType().equals(54) || task.getIoType().equals(57)){ LocCache locCache = locCacheService.selectOne(new EntityWrapper<LocCache>().eq("loc_no", task.getSourceLocNo())); if (Objects.isNull(locCache)) { @@ -669,6 +683,128 @@ return SUCCESS; } /** * 状态15(出库更新完成)时,生成空托出库或满托出库任务,将托盘放入缓存库位 * @param completedTask 已完成出库更新的任务(状态15) * @return 处理结果 */ @Transactional(rollbackFor = Exception.class) public ReturnT<String> generateEmptyOrFullPalletOutTaskForCompleted(Task completedTask) { // 只处理ioType=101的全板出库任务 if (!completedTask.getIoType().equals(101)) { return SUCCESS; } // 检查是否已经生成过空托/满托出库任务(避免重复生成) List<Task> existingTasks = taskService.selectList(new EntityWrapper<Task>() .eq("barcode", completedTask.getBarcode()) .in("io_type", 110, 101) // 空板出库或全板出库 .eq("wrk_sts", 7) // 待呼叫AGV状态 ); if (!existingTasks.isEmpty()) { log.info("任务ID:{}的托盘码:{}已存在空托/满托出库任务,跳过生成", completedTask.getId(), completedTask.getBarcode()); return SUCCESS; } try { generateEmptyOrFullPalletOutTask(completedTask, null); return SUCCESS; } catch (Exception e) { log.error("状态15时生成空托/满托出库任务失败,任务ID:{},错误:{}", completedTask.getId(), e.getMessage(), e); return FAIL.setMsg("生成空托/满托出库任务失败:" + e.getMessage()); } } /** * 出库完成后,生成空托出库或满托出库任务,将托盘放入缓存库位 * @param outTask 出库任务 * @param sourceLocCache 源库位(可为null) */ private void generateEmptyOrFullPalletOutTask(Task outTask, LocCache sourceLocCache) { // 判断托盘类型:空托或满托 boolean isEmptyPallet = "Y".equals(outTask.getEmptyMk()); Integer ioType = isEmptyPallet ? 110 : 101; // 110=空板出库,101=全板出库(满托出库) log.info("出库任务完成,生成{}任务,任务ID:{},托盘码:{}", isEmptyPallet ? "空托出库" : "满托出库", outTask.getId(), outTask.getBarcode()); // 分配缓存库位(whs_type=2) LocCache cacheLoc = locCacheService.selectOne(new EntityWrapper<LocCache>() .eq("whs_type", agvProperties.getWhsTypeMapping().getCacheArea()) // whs_type=2 缓存区 .eq("frozen", 0) .eq("loc_sts", LocStsType.LOC_STS_TYPE_O.type) // O.闲置 .ne("full_plt", isEmptyPallet ? "Y" : "N") // 空托不选满板库位,满托不选空板库位 .orderAsc(Arrays.asList("row1", "bay1", "lev1")) .last("OFFSET 0 ROWS FETCH NEXT 1 ROWS ONLY")); if (cacheLoc == null) { log.warn("没有可用的缓存库位,无法生成{}任务,任务ID:{}", isEmptyPallet ? "空托出库" : "满托出库", outTask.getId()); return; } // 获取出库站点(出库任务的staNo是出库站点,将作为空托/满托出库任务的源站点) String outboundStaNo = outTask.getStaNo(); if (outboundStaNo == null || outboundStaNo.isEmpty()) { log.warn("出库任务没有出库站点,无法生成{}任务,任务ID:{}", isEmptyPallet ? "空托出库" : "满托出库", outTask.getId()); return; } // 根据缓存区配置选择站点和机器人组(西侧) List<String> cacheStations = agvProperties.getWestStations(); String robotGroup = agvProperties.getRobotGroupWest(); if (cacheStations.isEmpty()) { log.warn("缓存区没有配置站点,无法生成{}任务,任务ID:{}", isEmptyPallet ? "空托出库" : "满托出库", outTask.getId()); return; } // 选择缓存区目标站点(使用第一个可用站点,或可以优化为选择任务最少的站点) String cacheStaNo = cacheStations.get(0); // 生成工作号 int workNo = commonService.getWorkNo(WorkNoType.PAKOUT.type); // 创建空托出库/满托出库任务 Task cacheTask = new Task(); Date now = new Date(); cacheTask.setWrkNo(workNo) .setIoTime(now) .setWrkSts(7L) // 工作状态:7.待呼叫AGV .setIoType(ioType) // 110=空板出库,101=全板出库 .setTaskType("agv") .setIoPri(10D) .setStaNo(cacheStaNo) // 目标站点(缓存区站点) .setSourceStaNo(outboundStaNo) // 源站点(出库站点) .setInvWh(robotGroup) // 机器人组(西侧) .setFullPlt(isEmptyPallet ? "N" : "Y") // 满板:空托=N,满托=Y .setPicking("N") .setExitMk("N") .setSourceLocNo(null) // 出库任务不需要源库位 .setLocNo(cacheLoc.getLocNo()) // 目标库位(缓存库位) .setEmptyMk(isEmptyPallet ? "Y" : "N") // 空板标记 .setBarcode(outTask.getBarcode()) // 托盘码 .setLinkMis("N") .setAppeTime(now) .setModiTime(now); if (!taskService.insert(cacheTask)) { log.error("生成{}任务失败,任务ID:{}", isEmptyPallet ? "空托出库" : "满托出库", outTask.getId()); return; } // 更新缓存库位状态:O.闲置 → S.入库预约 cacheLoc.setLocSts(LocStsType.LOC_STS_TYPE_S.type); cacheLoc.setBarcode(outTask.getBarcode()); cacheLoc.setModiTime(now); if (!locCacheService.updateById(cacheLoc)) { log.error("更新缓存库位状态失败,库位:{}", cacheLoc.getLocNo()); // 回滚任务 taskService.deleteById(cacheTask.getId()); return; } log.info("成功生成{}任务,任务ID:{},工作号:{},源站点:{},目标站点:{},缓存库位:{}", isEmptyPallet ? "空托出库" : "满托出库", cacheTask.getId(), workNo, outboundStaNo, cacheStaNo, cacheLoc.getLocNo()); } @Transactional(rollbackFor = Exception.class) public ReturnT<String> agvDoIn(Task wrkMast) { src/main/java/com/zy/common/properties/SchedulerProperties.java
New file @@ -0,0 +1,23 @@ package com.zy.common.properties; import lombok.Data; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.context.annotation.Configuration; /** * 定时任务配置属性 * * @author system */ @Data @Configuration @ConfigurationProperties(prefix = "scheduler") public class SchedulerProperties { /** * 定时任务总开关,false时所有定时任务都不会启动 * 默认值为true,保持向后兼容 */ private boolean enabled = true; } src/main/java/com/zy/system/timer/LicenseTimer.java
@@ -2,6 +2,7 @@ import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSONObject; import com.zy.common.properties.SchedulerProperties; import com.zy.common.utils.HttpHandler; import com.zy.system.entity.LicenseInfos; import com.zy.system.entity.license.*; @@ -12,6 +13,7 @@ import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Component; import javax.annotation.Resource; import java.util.Date; import java.util.HashMap; @@ -50,9 +52,15 @@ @Autowired private LicenseInfosService licenseInfosService; @Resource private SchedulerProperties schedulerProperties; //每天晚上11点更新系统激活状态 @Scheduled(cron = "0 0 23 * * ? ") public void timer() { if (!schedulerProperties.isEnabled()) { return; } try { getRemoteLicense(); } catch (Exception e) { src/main/java/com/zy/system/timer/LoadingConfigTimer.java
@@ -1,11 +1,14 @@ package com.zy.system.timer; import com.zy.common.properties.SchedulerProperties; import com.zy.system.service.ConfigService; import lombok.Data; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Component; import javax.annotation.Resource; /** * 定时任务读取配置信息 @@ -39,8 +42,14 @@ @Autowired private ConfigService configService; @Resource private SchedulerProperties schedulerProperties; @Scheduled(cron = "0/2 * * * * ? ") public void timer() { if (!schedulerProperties.isEnabled()) { return; } tokenExpire = configService.getVal("tokenExpire", Integer.class, tokenExpire); tokenNumber = configService.getVal("tokenNumber", Integer.class, tokenNumber); logDeleteDays = configService.getVal("logDeleteDays", Integer.class, logDeleteDays); src/main/java/com/zy/system/timer/TokenTimer.java
@@ -2,6 +2,7 @@ import com.baomidou.mybatisplus.mapper.EntityWrapper; import com.core.common.Cools; import com.zy.common.properties.SchedulerProperties; import com.zy.system.entity.UserLogin; import com.zy.system.service.UserLoginService; import lombok.extern.slf4j.Slf4j; @@ -10,6 +11,7 @@ import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Component; import javax.annotation.Resource; import java.util.List; /** @@ -28,8 +30,14 @@ @Value("${super.pwd}") private String superPwd; @Resource private SchedulerProperties schedulerProperties; @Scheduled(cron = "0/30 * * * * ? ") public void timer() { if (!schedulerProperties.isEnabled()) { return; } if (loadingConfigTimer.getTokenNumber() == 1) { return; } src/main/resources/application-dev.yml
@@ -106,4 +106,8 @@ # 虚拟库位编号 virtual-location-no: VIRTUAL # 定时任务配置 scheduler: # 定时任务总开关,false时所有定时任务都不会启动 enabled: true src/main/resources/application-prod.yml
@@ -105,3 +105,8 @@ outbound-doc-type-id: 36 # 虚拟库位编号 virtual-location-no: VIRTUAL # 定时任务配置 scheduler: # 定时任务总开关,false时所有定时任务都不会启动 enabled: true src/main/resources/mapper/TaskMapper.xml
@@ -34,7 +34,7 @@ <select id="selectToBeCompleteData" resultMap="BaseResultMap"> select * from agv_task where ((wrk_sts = 4 Or wrk_sts = 14 ) and io_type != 103 and io_type != 104 and io_type != 107 ) or (wrk_sts = 2 and io_type=6) order by upd_mk,error_time,io_time,wrk_no select * from agv_task where ((wrk_sts = 4 Or wrk_sts = 14 Or wrk_sts = 15 ) and io_type != 103 and io_type != 104 and io_type != 107 ) or (wrk_sts = 2 and io_type=6) order by upd_mk,error_time,io_time,wrk_no </select>