| src/main/java/com/zy/asrs/entity/Task.java | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| src/main/java/com/zy/asrs/entity/TaskLog.java | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| src/main/java/com/zy/asrs/task/AgvScheduler.java | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| src/main/java/com/zy/asrs/task/handler/AgvHandler.java | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| src/main/java/com/zy/common/constant/ApiInterfaceConstant.java | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| src/main/resources/mapper/TaskMapper.xml | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 |
src/main/java/com/zy/asrs/entity/Task.java
@@ -267,6 +267,13 @@ @ApiModelProperty(value = "") @TableField("error_memo") private String errorMemo; @ApiModelProperty(value = "") @TableField("error_time2") private Date errorTime2; @ApiModelProperty(value = "") @TableField("error_memo2") private String errorMemo2; @ApiModelProperty(value = "") @TableField("ctn_kind") src/main/java/com/zy/asrs/entity/TaskLog.java
@@ -274,6 +274,14 @@ @ApiModelProperty(value = "") @TableField("error_memo") private String errorMemo; @ApiModelProperty(value = "") @TableField("error_time2") private Date errorTime2; @ApiModelProperty(value = "") @TableField("error_memo2") private String errorMemo2; @ApiModelProperty(value = "") @TableField("ctn_kind") src/main/java/com/zy/asrs/task/AgvScheduler.java
@@ -1,5 +1,7 @@ package com.zy.asrs.task; import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSONObject; import com.baomidou.mybatisplus.mapper.EntityWrapper; import com.baomidou.mybatisplus.mapper.Wrapper; import com.core.common.Cools; @@ -11,7 +13,9 @@ import com.zy.asrs.service.WrkMastLogService; import com.zy.asrs.service.WrkMastService; import com.zy.asrs.task.handler.AgvHandler; import com.zy.common.constant.ApiInterfaceConstant; import com.zy.common.properties.SchedulerProperties; import com.zy.common.utils.HttpHandler; import com.zy.system.entity.Config; import com.zy.system.service.ConfigService; import lombok.extern.slf4j.Slf4j; @@ -19,11 +23,14 @@ import org.springframework.stereotype.Component; import javax.annotation.Resource; import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.concurrent.atomic.AtomicBoolean; /** @@ -144,6 +151,7 @@ } catch (InterruptedException e) { Thread.currentThread().interrupt(); log.warn("定时任务allocateSite:延迟被中断", e); isAllocateSite.set(false); break; // 如果被中断,退出循环 } } @@ -202,7 +210,6 @@ displayTaskId, task.getWrkNo(), task.getIoType(), task.getStaNo()); boolean processed = agvHandler.callAgv(Collections.singletonList(task)); // 只有当任务成功处理(成功呼叫AGV,状态从7变为8)时,才更新lastProcessedTaskId // 如果任务被跳过(站点被占用等),不更新lastProcessedTaskId,下次会重新尝试 if (processed) { lastProcessedTaskId = task.getId(); @@ -218,6 +225,7 @@ } catch (InterruptedException e) { Thread.currentThread().interrupt(); log.warn("呼叫AGV定时任务:延迟被中断", e); isAllocateSite.set(false); break; // 如果被中断,退出循环 } } @@ -325,14 +333,16 @@ if (agvTask.getIoType() != null && (agvTask.getIoType() == 1 || agvTask.getIoType() == 10 || agvTask.getIoType() == 53 || agvTask.getIoType() == 57)) { // taskId使用工作号(wrk_no),如果工作号为空则使用任务ID String displayTaskId = (agvTask.getWrkNo() != null) ? String.valueOf(agvTask.getWrkNo()) : String.valueOf(agvTask.getId()); // 更新AGV任务状态为完成 agvTask.setWrkSts(9L); agvTask.setModiTime(now); if (taskService.updateById(agvTask)) { completedTasks.add(agvTask); completedCount++; // taskId使用工作号(wrk_no),如果工作号为空则使用任务ID String displayTaskId = (agvTask.getWrkNo() != null) ? String.valueOf(agvTask.getWrkNo()) : String.valueOf(agvTask.getId()); log.info("入库任务工作档已入库成功,完结AGV呼叫单,taskId:{},wrkNo:{},barcode:{}", displayTaskId, wrkMast.getWrkNo(), wrkMast.getBarcode()); } @@ -577,6 +587,36 @@ reason, displayTaskId, agvTask.getWrkNo(), agvTask.getBarcode(), agvTask.getStaNo()); } } // 检查订单创建时间,超过五分钟后才查询AGV订单状态 Date appeTime = agvTask.getAppeTime(); boolean shouldCheckAgvStatus = false; if (appeTime != null) { long timeDiff = now.getTime() - appeTime.getTime(); long fiveMinutesInMillis = 5 * 60 * 1000; // 5分钟 if (timeDiff >= fiveMinutesInMillis) { shouldCheckAgvStatus = true; } } else { // 如果没有创建时间,默认检查 shouldCheckAgvStatus = true; } // taskId使用工作号(wrk_no),如果工作号为空则使用任务ID String displayTaskId = (agvTask.getWrkNo() != null) ? String.valueOf(agvTask.getWrkNo()) : String.valueOf(agvTask.getId()); // 如果订单创建超过五分钟,查询AGV订单状态 if (shouldCheckAgvStatus) { String agvOrderStatus = queryAgvOrderStatus(agvTask, displayTaskId); if (agvOrderStatus != null) { // 根据订单状态处理 boolean shouldComplete = processAgvOrderStatus(agvTask, agvOrderStatus, displayTaskId, now); if (shouldComplete) { completedTasks.add(agvTask); } } } } // 立即将完成的AGV任务转移到历史表,不保留在Task表中 @@ -597,5 +637,177 @@ } } /** * 查询AGV订单状态 * @param agvTask AGV任务 * @param displayTaskId 显示的任务ID * @return 订单状态(Building/Created/Assigned/Failed/Done/Cancelled),如果查询失败返回null */ private String queryAgvOrderStatus(Task agvTask, String displayTaskId) { try { // 构建订单ID,格式为 "T" + wrkNo String orderId = null; if (agvTask.getWrkNo() != null) { orderId = "T" + agvTask.getWrkNo(); } else { String errorMsg = String.format("查询AGV订单状态失败:任务ID:%s,wrkNo为空", displayTaskId); log.warn("查询AGV订单状态失败 - 任务ID:{},{}", displayTaskId, errorMsg); agvTask.setErrorMemo(errorMsg); agvTask.setErrorTime(new Date()); taskService.updateById(agvTask); return null; } // 构建请求JSON JSONObject requestJson = new JSONObject(); requestJson.put("entityName", "ContainerTransportOrder"); requestJson.put("id", orderId); String requestBody = requestJson.toJSONString(); // 构建请求头 Map<String, Object> headers = new HashMap<>(); headers.put("xyy-app-id", "seer"); headers.put("xyy-app-key", "123456"); // 发送请求 String response = null; try { response = new HttpHandler.Builder() .setUri(ApiInterfaceConstant.AGV_IP) .setPath(ApiInterfaceConstant.AGV_FIND_ONE_PATH) .setJson(requestBody) .setHeaders(headers) .build() .doPost(); } catch (IOException e) { String errorMsg = String.format("查询AGV订单状态API调用失败:%s,请求:%s", e.getMessage(), requestBody); log.error("查询AGV订单状态失败 - 任务ID:{},订单ID:{},{}", displayTaskId, orderId, errorMsg, e); agvTask.setErrorMemo2(errorMsg); agvTask.setErrorTime2(new Date()); taskService.updateById(agvTask); return null; } // 解析响应 if (response == null || response.trim().isEmpty()) { String errorMsg = String.format("查询AGV订单状态API返回为空,请求:%s", requestBody); log.warn("查询AGV订单状态失败 - 任务ID:{},订单ID:{},{}", displayTaskId, orderId, errorMsg); agvTask.setErrorMemo2(errorMsg); agvTask.setErrorTime2(new Date()); taskService.updateById(agvTask); return null; } try { JSONObject responseJson = JSON.parseObject(response); // 检查是否有错误码 String code = responseJson.getString("code"); if (code != null && "errNoSuchEntity".equals(code)) { // 找不到业务对象,记录到errorMemo但忽略(不阻止后续处理) String errorMsg = String.format("查询AGV订单状态:找不到订单(errNoSuchEntity),请求:%s,响应:%s", requestBody, response); log.debug("查询AGV订单状态:找不到订单 - 任务ID:{},订单ID:{}", displayTaskId, orderId); agvTask.setErrorMemo2(errorMsg); agvTask.setErrorTime2(new Date()); taskService.updateById(agvTask); return null; } // 获取订单信息 JSONObject entityValue = responseJson.getJSONObject("entityValue"); if (entityValue != null) { String status = entityValue.getString("status"); if (status != null) { log.info("查询AGV订单状态成功 - 任务ID:{},订单ID:{},状态:{}", displayTaskId, orderId, status); return status; } else { String errorMsg = String.format("查询AGV订单状态响应中缺少status字段,请求:%s,响应:%s", requestBody, response); log.warn("查询AGV订单状态失败 - 任务ID:{},订单ID:{},{}", displayTaskId, orderId, errorMsg); agvTask.setErrorMemo2(errorMsg); agvTask.setErrorTime2(new Date()); taskService.updateById(agvTask); return null; } } else { String errorMsg = String.format("查询AGV订单状态响应中缺少entityValue字段,请求:%s,响应:%s", requestBody, response); log.warn("查询AGV订单状态失败 - 任务ID:{},订单ID:{},{}", displayTaskId, orderId, errorMsg); agvTask.setErrorMemo2(errorMsg); agvTask.setErrorTime2(new Date()); taskService.updateById(agvTask); return null; } } catch (com.alibaba.fastjson.JSONException e) { String errorMsg = String.format("解析AGV订单状态响应JSON失败:%s,请求:%s,响应:%s", e.getMessage(), requestBody, response); log.error("查询AGV订单状态失败 - 任务ID:{},订单ID:{},{}", displayTaskId, orderId, errorMsg, e); agvTask.setErrorMemo2(errorMsg); agvTask.setErrorTime2(new Date()); taskService.updateById(agvTask); return null; } } catch (Exception e) { String errorMsg = String.format("查询AGV订单状态异常:%s", e.getMessage()); log.error("查询AGV订单状态异常 - 任务ID:{},{}", displayTaskId, errorMsg, e); agvTask.setErrorMemo2(errorMsg); agvTask.setErrorTime2(new Date()); taskService.updateById(agvTask); return null; } } /** * 处理AGV订单状态 * @param agvTask AGV任务 * @param status 订单状态 * @param displayTaskId 显示的任务ID * @param now 当前时间 * @return true表示应该完结订单,false表示不应该完结(跳过) */ private boolean processAgvOrderStatus(Task agvTask, String status, String displayTaskId, Date now) { if (status == null) { return false; // 状态为空,跳过 } switch (status) { case "Building": // Building=未提交,正常没有此状态,忽略 log.debug("AGV订单状态为Building(未提交),忽略 - 任务ID:{}", displayTaskId); return true; // 继续处理 case "Created": // Created=已提交,等待期间,不处理 log.debug("AGV订单状态为Created(已提交),等待期间,不处理 - 任务ID:{}", displayTaskId); return false; // 不处理,跳过 case "Assigned": case "Assined": // Assigned=已派车,正常状态,不处理 log.debug("AGV订单状态为{}(已派车),正常状态,不处理 - 任务ID:{}", status, displayTaskId); return false; // 不处理,跳过 case "Failed": case "Failde": // Failed=失败,标记为失败订单 log.warn("AGV订单状态为{}(失败),标记为失败订单 - 任务ID:{}", status, displayTaskId); agvTask.setWrkSts(10L); agvTask.setErrorTime(now); agvTask.setErrorMemo(String.format("AGV订单状态为%s(失败)", status)); taskService.updateById(agvTask); return false; // 不处理,跳过 case "Done": // Done=已完成,完结订单 log.info("AGV订单状态为Done(已完成),完结订单 - 任务ID:{}", displayTaskId); return true; // 继续处理,完结订单 case "Cancelled": // Cancelled=取消,取消订单 log.warn("AGV订单状态为Cancelled(取消),取消订单 - 任务ID:{}", displayTaskId); agvTask.setWrkSts(10L); agvTask.setErrorTime(now); agvTask.setErrorMemo("AGV订单状态为Cancelled(取消)"); taskService.updateById(agvTask); return false; // 不处理,跳过 default: // 未知状态,记录日志但继续处理 log.warn("AGV订单状态未知:{},继续处理 - 任务ID:{}", status, displayTaskId); return true; // 继续处理 } } } src/main/java/com/zy/asrs/task/handler/AgvHandler.java
@@ -80,7 +80,7 @@ /** * 呼叫AGV * * <p> * 重要:此方法只能从 AgvScheduler.callAgv() 定时任务中调用! * 所有AGV呼叫请求必须通过定时任务统一处理,确保: * 1. 任务按顺序处理,避免并发冲突 @@ -350,14 +350,6 @@ return true; // 已达到最大重试次数,不再重试,返回true表示已处理(虽然失败) } // 打印请求信息(包含重试次数) // if (currentRetryCount > 0) { // log.info("{}呼叫agv搬运(第{}次重试) - 请求地址:{}", namespace, currentRetryCount + 1, url); // } else { // log.info("{}呼叫agv搬运 - 请求地址:{}", namespace, url); // } // log.info("{}呼叫agv搬运 - 请求参数:{}", namespace, body); boolean result = false; // 默认返回false,表示未成功处理 try { // 使用仙工M4接口 @@ -368,23 +360,16 @@ .build() .doPost(); // 打印返回参数 log.info("{}呼叫agv搬运,请求参数「{}」 - 返回参数:{}", namespace,body, response); log.info("仙工-{}呼叫agv搬运,请求参数「{}」 - 返回参数:{}", namespace, body, response); // 检查响应是否为空 if (response == null || response.trim().isEmpty()) { String errorMsg = "AGV接口返回为空"; log.warn("定时任务:{}呼叫agv搬运失败 - 任务ID:{},{}", namespace, displayTaskId, errorMsg); handleCallFailure(task, namespace, errorMsg, retryEnabled, maxRetryCount, currentRetryCount); // 如果达到最大重试次数,返回true表示已处理(虽然失败) // 否则返回false,让定时任务重新尝试 if (retryEnabled && currentRetryCount >= maxRetryCount) { result = true; // 已达到最大重试次数,返回true表示已处理(虽然失败) log.info("定时任务:任务ID:{},AGV呼叫失败且已达到最大重试次数({}次),标记为已处理,不再重试", displayTaskId, maxRetryCount); } else { result = false; // 返回false,让定时任务重新尝试 log.info("定时任务:任务ID:{},下次将重新尝试发送AGV命令", displayTaskId); } task.setWrkSts(10L); task.setErrorTime(new Date()); task.setErrorMemo(String.format("AGV接口返回为空")); taskService.updateById(task); } else { // 尝试解析JSON响应,捕获JSON解析异常 JSONObject jsonObject = null; @@ -394,44 +379,10 @@ // JSON解析失败,响应可能不是有效的JSON格式(如"Server Error"等) String errorMsg = String.format("AGV接口返回非JSON格式响应,响应内容:%s,解析错误:%s", response, e.getMessage()); log.error("定时任务:{}呼叫agv搬运失败 - 任务ID:{},{}", namespace, displayTaskId, errorMsg); // 服务器错误时,标记站点为不可用,清空站点分配,不再为当前任务分配站点 try { Integer siteNo = Integer.parseInt(staNo); // 查询站点信息 List<BasDevp> basDevpList = basDevpMapper.selectList(new EntityWrapper<BasDevp>().eq("dev_no", siteNo)); if (basDevpList != null && !basDevpList.isEmpty()) { BasDevp basDevp = basDevpList.get(0); // 标记站点为不可用(设置canining='N') basDevp.setCanining("N"); basDevpMapper.updateById(basDevp); log.warn("定时任务:任务ID:{},AGV接口返回服务器错误,已标记站点{}为不可用(canining='N')", displayTaskId, siteNo); // 减少站点的入库任务数(之前分配站点时已经增加了in_qty) basDevpMapper.decrementInQty(siteNo); log.debug("定时任务:任务ID:{},站点{}的in_qty已减少", displayTaskId, siteNo); } } catch (Exception ex) { log.error("定时任务:任务ID:{},标记站点{}为不可用时发生异常:{}", displayTaskId, staNo, ex.getMessage()); } // 清空当前任务的站点分配 log.warn("定时任务:任务ID:{},AGV接口返回服务器错误,清空站点分配:{},不再为当前任务分配站点", displayTaskId, staNo); task.setStaNo(null); taskService.updateById(task); // 标记任务为失败,不再尝试分配 task.setWrkSts(10L); task.setErrorTime(new Date()); task.setErrorMemo(String.format("AGV接口返回服务器错误,站点已标记为不可用:%s", errorMsg)); task.setErrorMemo(errorMsg); taskService.updateById(task); handleCallFailure(task, namespace, errorMsg, retryEnabled, maxRetryCount, currentRetryCount); // 服务器错误时,不再尝试分配,直接标记为已处理 result = true; // 返回true表示已处理(虽然失败),不再尝试分配 log.info("定时任务:任务ID:{},AGV呼叫失败(服务器错误),站点已标记为不可用,任务已标记为失败,不再尝试分配", displayTaskId); } // 如果JSON解析成功,继续处理 @@ -444,13 +395,15 @@ Long currentStatus = task.getWrkSts(); if (currentStatus == null || currentStatus != 8L) { task.setWrkSts(8L); log.info("定时任务:{}呼叫agv搬运成功 - 任务ID:{},状态从{}更新为8", namespace, displayTaskId, currentStatus); } else { log.info("定时任务:{}呼叫agv搬运成功(重试) - 任务ID:{},状态保持为8", namespace, displayTaskId); } task.setLocNo(task.getStaNo()); task.setMemo(clearRetryInfo(task.getMemo())); // 清除重试信息 task.setErrorTime(null); task.setErrorMemo(null); task.setErrorTime(new Date()); task.setErrorMemo(jsonObject.toJSONString()); taskService.updateById(task); log.info("定时任务:{}呼叫agv搬运成功 - 任务ID:{}", namespace, displayTaskId); result = true; // 返回true,表示成功处理 @@ -459,44 +412,12 @@ String errorMsg = String.format("错误码:%s,错误信息:%s", code, message); log.warn("定时任务:{}呼叫agv搬运失败 - 任务ID:{},{}", namespace, displayTaskId, errorMsg); // 检查是否是站点或库位相关的错误,如果是,清空站点分配,让定时任务重新分配 boolean shouldReallocateSite = false; if (message != null) { String lowerMessage = message.toLowerCase(); // 库位不存在、站点不存在等错误,应该重新分配站点 if (lowerMessage.contains("库位不存在") || lowerMessage.contains("站点不存在") || lowerMessage.contains("位置不存在") || lowerMessage.contains("库位无效") || lowerMessage.contains("站点无效")) { shouldReallocateSite = true; } } if (shouldReallocateSite) { // 清空站点分配,让定时任务重新分配站点 log.warn("定时任务:任务ID:{},AGV呼叫失败({}),清空站点分配:{},下次将重新分配站点", displayTaskId, errorMsg, staNo); task.setStaNo(null); task.setWrkSts(10L); task.setLocNo(task.getStaNo()); task.setErrorTime(new Date()); task.setErrorMemo(jsonObject.toJSONString()); taskService.updateById(task); } handleCallFailure(task, namespace, errorMsg, retryEnabled, maxRetryCount, currentRetryCount); // 如果达到最大重试次数,返回true表示已处理(虽然失败) // 否则返回false,让定时任务重新尝试(如果站点被清空,会重新分配站点;如果站点未清空,会重新发送AGV) if (retryEnabled && currentRetryCount >= maxRetryCount) { result = true; // 已达到最大重试次数,返回true表示已处理(虽然失败) log.info("定时任务:任务ID:{},AGV呼叫失败且已达到最大重试次数({}次),标记为已处理,不再重试", displayTaskId, maxRetryCount); } else { result = false; // 返回false,让定时任务重新尝试(重新分配站点或重新发送AGV) if (shouldReallocateSite) { log.info("定时任务:任务ID:{},站点已清空,下次将重新分配站点", displayTaskId); } else { log.info("定时任务:任务ID:{},下次将重新尝试发送AGV命令", displayTaskId); } } } } } @@ -504,16 +425,15 @@ String errorMsg = "异常信息:" + e.getMessage(); log.error("定时任务:{}呼叫agv搬运异常 - 任务ID:{},请求地址:{},请求参数:{},{}", namespace, displayTaskId, url, body, errorMsg, e); handleCallFailure(task, namespace, errorMsg, retryEnabled, maxRetryCount, currentRetryCount); // 如果达到最大重试次数,返回true表示已处理(虽然失败) // 否则返回false,让定时任务重新尝试 if (retryEnabled && currentRetryCount >= maxRetryCount) { result = true; // 已达到最大重试次数,返回true表示已处理(虽然失败) log.info("定时任务:任务ID:{},AGV呼叫异常且已达到最大重试次数({}次),标记为已处理,不再重试", displayTaskId, maxRetryCount); if (errorMsg.contains("connect timed out")) { log.error("定时任务:{}呼叫agv搬运异常 - 任务ID:{},网络请求超时", namespace, displayTaskId); } else { result = false; // 返回false,让定时任务重新尝试 log.info("定时任务:任务ID:{},下次将重新尝试发送AGV命令", displayTaskId); task.setWrkSts(10L); task.setLocNo(task.getStaNo()); task.setErrorTime(new Date()); task.setErrorMemo(errorMsg); taskService.updateById(task); } } finally { try { @@ -536,6 +456,7 @@ /** * 处理AGV呼叫失败的情况 * * @param task 任务对象 * @param namespace 命名空间(入库/出库/转移) * @param errorMsg 错误信息 @@ -571,6 +492,7 @@ /** * 检查并自动结束已完成工作档的AGV任务 * 如果任务对应的工作档已经完成(入库成功),则自动结束该AGV任务 * * @param transportingTasks 正在搬运的任务列表 * @param taskTypeName 任务类型名称(用于日志) * @return 仍然有效的正在搬运的任务列表(已完成的已被移除) @@ -678,10 +600,10 @@ } /** * 从memo字段中获取重试次数 * memo格式:如果包含"retryCount:数字",则返回该数字,否则返回0 * * @param task 任务对象 * @return 重试次数 */ @@ -711,6 +633,7 @@ /** * 更新memo字段中的重试次数 * * @param memo 原始memo内容 * @param retryCount 新的重试次数 * @return 更新后的memo内容 @@ -731,6 +654,7 @@ /** * 清除memo字段中的重试信息 * * @param memo 原始memo内容 * @return 清除后的memo内容 */ @@ -800,6 +724,7 @@ /** * 为任务分配站点(定时任务中调用) * 注意:只会分配一个站点,找到第一个符合条件的站点就分配并退出 * * @param task 任务对象 * @return 如果无法分配站点,返回错误信息;如果分配成功,返回null并更新task的staNo */ @@ -844,48 +769,10 @@ displayTaskId, groupKey.equals("east") ? agvProperties.getEastDisplayName() : agvProperties.getWestDisplayName(), targetStations, targetStations.size()); // 判断能入站点(in_enable="Y"表示能入),排除dev_no=0的无效站点 List<BasDevp> allDevList = basDevpMapper.selectList( new EntityWrapper<BasDevp>() .in("dev_no", siteIntList) .ne("dev_no", 0) // 排除dev_no=0的无效站点 ); // 记录所有站点的状态信息 StringBuilder siteStatusInfo = new StringBuilder(); for (BasDevp dev : allDevList) { if (siteStatusInfo.length() > 0) { siteStatusInfo.append("; "); } siteStatusInfo.append("站点").append(dev.getDevNo()) .append("(in_enable=").append(dev.getInEnable()) .append(",canining=").append(dev.getCanining()).append(")"); } log.info("任务ID:{},候选站点状态:{}", displayTaskId, siteStatusInfo.toString()); List<Integer> sites = allDevList.stream() .filter(dev -> "Y".equals(dev.getInEnable())) .map(BasDevp::getDevNo) .filter(devNo -> devNo != null && devNo != 0) // 再次过滤,确保不为null或0 .collect(Collectors.toList()); // 检查是否有站点不可用,如果有,说明需要在可用的站点之间平均分配 List<Integer> unavailableSites = new ArrayList<>(siteIntList); unavailableSites.removeAll(sites); if (!unavailableSites.isEmpty()) { log.info("任务ID:{},{}站点组中有{}个站点不可用(in_enable!='Y'):{},将在{}个可用站点之间平均分配", displayTaskId, groupKey.equals("east") ? agvProperties.getEastDisplayName() : agvProperties.getWestDisplayName(), unavailableSites.size(), unavailableSites, sites.size()); } if (sites.isEmpty()) { String errorMsg = "没有能入站点(in_enable='Y')"; log.warn("任务ID:{},{},候选站点列表:{},站点状态:{}", displayTaskId, errorMsg, targetStations, siteStatusInfo.toString()); return errorMsg; } // 先检查站点配置(canining="Y"可入),排除dev_no=0的无效站点 List<BasDevp> devListWithConfig = basDevpMapper.selectList(new EntityWrapper<BasDevp>() .in("dev_no", sites) .in("dev_no", siteIntList) .eq("in_enable", "Y") .eq("canining", "Y") .eq("loading", "N") @@ -893,8 +780,8 @@ ); if (devListWithConfig==null || devListWithConfig.isEmpty()) { log.warn("任务ID:{}没有可入站点(站点未开通可入允许:canining='Y'),暂不分配站点,等待配置开通。能入站点列表:{}", displayTaskId, sites); log.warn("任务ID:{}没有可入站点(站点未开通可入允许:canining='Y'),暂不分配站点,等待配置开通。站点列表:{}", displayTaskId, targetStations); return null; } @@ -1042,8 +929,10 @@ log.info("任务ID:{}已分配站点:{},机器人组:{},任务类型:{}", displayTaskId, endSite, robotGroup, taskTypeName); return null; // 分配成功,返回null } /** * 根据站点编号判断机器人组 * * @param staNo 站点编号 * @return 机器人组名称 */ @@ -1134,11 +1023,13 @@ log.info("agv任务档转历史成功:{}", taskIds); } @Transactional(rollbackFor = Exception.class) public void moveTaskToHistory(Task agvTask) { moveTaskToHistory(Collections.singletonList(agvTask)); } /** * 货物到达出库口,生成agv任务 */ @@ -1165,6 +1056,7 @@ /** * 取消AGV任务(仙工M4接口) * * @param task 任务对象 * @return 是否成功 */ src/main/java/com/zy/common/constant/ApiInterfaceConstant.java
@@ -46,4 +46,11 @@ */ public static final String AGV_CANCEL_TASK_PATH = "/api/agv/cancelTransport"; /* ***************************************Falcon接口对接 start*******************************************************/ /** * agv - 查询订单状态 */ public static final String AGV_FIND_ONE_PATH = "/api/entity/find/one"; } src/main/resources/mapper/TaskMapper.xml
@@ -34,13 +34,13 @@ <select id="selectToBeCompleteData" resultMap="BaseResultMap"> 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 * from agv_task where is_deleted = 0 and(((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> <select id="selectToBeHistoryData" resultMap="BaseResultMap"> select * from agv_task where wrk_sts=5 or wrk_sts=15 where is_deleted = 0 and( wrk_sts=5 or wrk_sts=15) order by io_time,wrk_no asc </select> </mapper>