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;
|
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.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;
|
import org.springframework.scheduling.annotation.Scheduled;
|
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;
|
|
/**
|
* @author pang.jiabao
|
* @description AGV交互相关定时任务
|
* @createDate 2025/11/18 14:18
|
*/
|
@Slf4j
|
@Component
|
public class AgvScheduler {
|
|
@Resource
|
private ConfigService configService;
|
|
@Resource
|
private AgvHandler agvHandler;
|
|
@Resource
|
private TaskService taskService;
|
|
@Resource
|
private WrkMastMapper wrkMastMapper;
|
|
@Resource
|
private WrkMastService wrkMastService;
|
|
@Resource
|
private WrkMastLogService wrkMastLogService;
|
|
@Resource
|
private SchedulerProperties schedulerProperties;
|
|
/**
|
* 记录上次处理的任务ID,用于轮询处理
|
* 确保每次处理不同的任务,避免一直处理同一个任务
|
*/
|
private Long lastProcessedTaskId = null;
|
|
/**
|
* 记录上次分配站点的任务ID,用于轮询处理
|
*/
|
private Long lastAllocatedTaskId = null;
|
|
/**
|
* 分配站点任务执行标志,确保同一时间只有一个线程在执行分配站点循环
|
*/
|
private final AtomicBoolean isAllocateSite = new AtomicBoolean(false);
|
/**
|
* 呼叫AGV定时任务执行标志,确保同一时间只有一个线程在执行分配站点循环
|
*/
|
private final AtomicBoolean iscallAgv = new AtomicBoolean(false);
|
|
/**
|
* agv工作档分配站点定时任务
|
* 查询状态7(待呼叫AGV)但没有分配站点的任务,为其分配可用站点
|
* 只负责分配站点,不呼叫AGV
|
* 每次只处理一个任务,避免高并发执行
|
* 使用AtomicBoolean确保单线程执行循环
|
*/
|
@Scheduled(cron = "0/5 * * * * ? ")
|
private void allocateSite() {
|
if (!schedulerProperties.isEnabled()) {
|
log.debug("定时任务allocateSite:调度器未启用,跳过执行");
|
return;
|
}
|
if (!isAllocateSite.compareAndSet(false, true)) {
|
log.debug("定时任务allocateSite:上一次分配站点任务还在执行中,跳过本次执行");
|
return;
|
}
|
// 构建查询条件:查询所有待呼叫AGV但没有分配站点的任务
|
EntityWrapper<Task> wrapper = new EntityWrapper<Task>();
|
wrapper.eq("wrk_sts", 7); // 待呼叫AGV状态
|
wrapper.eq("task_type", "agv"); // AGV任务类型
|
wrapper.eq("is_deleted", 0); // 排除已删除的任务
|
wrapper.andNew()
|
.isNull("sta_no")
|
.or()
|
.eq("sta_no", "")
|
.or()
|
.eq("sta_no", "0");
|
wrapper.orderBy("id", true); // 按id升序排序
|
wrapper.last("OFFSET 0 ROWS FETCH NEXT 21 ROWS ONLY");
|
List<Task> taskList = taskService.selectList(wrapper);
|
|
|
if (taskList.isEmpty()) {
|
log.debug("定时任务allocateSite:没有待分配站点的任务(wrk_sts=7,task_type=agv,sta_no为空)");
|
isAllocateSite.set(false);
|
return;
|
}
|
|
|
try {
|
for (Task task : taskList) {
|
String errorMsg = agvHandler.allocateSiteForTask(task);
|
// 调用分配站点逻辑
|
|
String displayTaskId = (task.getWrkNo() != null) ? String.valueOf(task.getWrkNo()) : String.valueOf(task.getId());
|
log.info("定时任务allocateSite:开始为任务ID:{}分配站点(wrk_no={},ioType={})",
|
displayTaskId, task.getWrkNo(), task.getIoType());
|
|
// 检查是否成功分配了站点
|
String staNo = task.getStaNo();
|
if (errorMsg == null && staNo != null && !staNo.isEmpty() && !staNo.equals("0")) {
|
// 分配站点成功
|
lastAllocatedTaskId = task.getId();
|
log.info("定时任务allocateSite:任务ID:{}成功分配站点:{},更新lastAllocatedTaskId为{}",
|
displayTaskId, staNo, lastAllocatedTaskId);
|
} else {
|
// 无法分配站点,不更新lastAllocatedTaskId,下次会重新尝试
|
log.info("定时任务allocateSite:任务ID:{}无法分配站点:{},不更新lastAllocatedTaskId(当前:{}),下次将重新尝试",
|
displayTaskId, errorMsg != null ? errorMsg : "所有站点都被占用", lastAllocatedTaskId);
|
}
|
|
// 每个任务处理完后等待1秒,
|
try {
|
Thread.sleep(1000);
|
} catch (InterruptedException e) {
|
Thread.currentThread().interrupt();
|
log.warn("定时任务allocateSite:延迟被中断", e);
|
isAllocateSite.set(false);
|
break; // 如果被中断,退出循环
|
}
|
}
|
} finally {
|
// 确保标志位被重置,即使发生异常也能释放锁
|
isAllocateSite.set(false);
|
}
|
|
|
}
|
|
/**
|
* 呼叫AGV定时任务
|
* 查询状态7(待呼叫AGV)且已分配站点的任务,呼叫AGV
|
* 呼叫成功后,状态从7(待呼叫AGV)变为8(正在搬运)
|
*/
|
@Scheduled(cron = "0/5 * * * * ? ")
|
private void callAgv() {
|
if (!schedulerProperties.isEnabled()) {
|
log.debug("呼叫AGV定时任务:调度器未启用,跳过执行");
|
return;
|
}
|
if (!iscallAgv.compareAndSet(false, true)) {
|
log.debug("呼叫AGV定时任务:上一次分配站点任务还在执行中,跳过本次执行");
|
return;
|
}
|
try {
|
// 构建查询条件:查询状态7(待呼叫AGV)且已分配站点的任务
|
EntityWrapper<Task> wrapper = new EntityWrapper<Task>();
|
wrapper.eq("wrk_sts", 7); // 待呼叫AGV状态
|
wrapper.eq("task_type", "agv"); // AGV任务类型
|
wrapper.eq("is_deleted", 0); // 排除已删除的任务
|
wrapper.isNotNull("sta_no"); // 必须有站点分配
|
wrapper.ne("sta_no", ""); // 站点不能为空字符串
|
wrapper.ne("sta_no", "0"); // 站点不能为0
|
wrapper.orderBy("id", true); // 按id升序排序
|
wrapper.last("OFFSET 0 ROWS FETCH NEXT 22 ROWS ONLY");
|
// 如果上次处理过任务,从下一个任务开始查询(轮询)
|
// if (lastProcessedTaskId != null) {
|
// wrapper.gt("id", lastProcessedTaskId);
|
// }
|
|
// 查询待呼叫agv任务
|
List<Task> taskList = taskService.selectList(wrapper);
|
|
|
if (taskList.isEmpty()) {
|
log.debug("呼叫AGV定时任务:没有待呼叫AGV的任务(wrk_sts=7,task_type=agv,sta_no不为空)");
|
iscallAgv.set(false);
|
return;
|
}
|
for (Task task : taskList) {
|
// 调用处理逻辑:呼叫AGV,成功后状态从7变为8
|
String displayTaskId = (task.getWrkNo() != null) ? String.valueOf(task.getWrkNo()) : String.valueOf(task.getId());
|
log.info("呼叫AGV定时任务:开始处理任务ID:{}(wrk_no={},ioType={},sta_no={})",
|
displayTaskId, task.getWrkNo(), task.getIoType(), task.getStaNo());
|
boolean processed = agvHandler.callAgv(Collections.singletonList(task));
|
|
// 如果任务被跳过(站点被占用等),不更新lastProcessedTaskId,下次会重新尝试
|
if (processed) {
|
lastProcessedTaskId = task.getId();
|
log.info("定时任务callAgv:任务ID:{}成功呼叫AGV,状态已从7变为8,更新lastProcessedTaskId为{},下次将处理下一个任务",
|
displayTaskId, lastProcessedTaskId);
|
} else {
|
log.info("定时任务callAgv:任务ID:{}被跳过,不更新lastProcessedTaskId(当前:{}),下次将重新尝试处理此任务",
|
displayTaskId, lastProcessedTaskId);
|
}
|
// 每个任务处理完后等待1秒,
|
try {
|
Thread.sleep(1000);
|
} catch (InterruptedException e) {
|
Thread.currentThread().interrupt();
|
log.warn("呼叫AGV定时任务:延迟被中断", e);
|
isAllocateSite.set(false);
|
break; // 如果被中断,退出循环
|
}
|
}
|
} finally {
|
// 确保标志位被重置,即使发生异常也能释放锁
|
iscallAgv.set(false);
|
}
|
}
|
|
/**
|
* 货物到达出库口,生成agv任务
|
*/
|
@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));
|
if (configs.isEmpty()) {
|
return;
|
}
|
|
// 获取agv出库可用站点
|
List<String> sites = new ArrayList<>();
|
for (Config config : configs) {
|
String value = config.getValue();
|
if (Cools.isEmpty(value)) {
|
continue;
|
}
|
String[] split = value.split(";");
|
sites.addAll(Arrays.asList(split));
|
}
|
|
if (sites.isEmpty()) {
|
return;
|
}
|
|
agvHandler.createAgvOutTasks(sites);
|
}
|
|
/**
|
* 任务完成转历史
|
*/
|
@Scheduled(cron = "0/10 * * * * ? ")
|
private void moveTaskToHistory() {
|
if (!schedulerProperties.isEnabled()) {
|
return;
|
}
|
List<Task> taskList = taskService.selectList(new EntityWrapper<Task>().eq("wrk_sts", 9).eq("is_deleted", 0));
|
if (taskList.isEmpty()) {
|
return;
|
}
|
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;
|
List<Task> completedTasks = new ArrayList<>();
|
|
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())
|
.eq("is_deleted", 0); // 排除已删除的任务
|
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())
|
.eq("is_deleted", 0); // 排除已删除的任务
|
agvTasks = taskService.selectList(taskWrapper2);
|
}
|
|
for (Task agvTask : agvTasks) {
|
// 确保是入库任务
|
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++;
|
log.info("入库任务工作档已入库成功,完结AGV呼叫单,taskId:{},wrkNo:{},barcode:{}",
|
displayTaskId, wrkMast.getWrkNo(), wrkMast.getBarcode());
|
}
|
}
|
}
|
}
|
|
// 立即将完成的AGV任务转移到历史表,不保留在Task表中
|
if (!completedTasks.isEmpty()) {
|
try {
|
agvHandler.moveTaskToHistory(completedTasks);
|
log.info("入库完成,已将{}个AGV任务转移到历史表(不保留在Task表中)", completedTasks.size());
|
} catch (Exception e) {
|
log.error("入库完成,转移AGV任务到历史表失败", e);
|
}
|
}
|
|
if (completedCount > 0) {
|
log.info("本次检查完结了{}个入库AGV呼叫单", completedCount);
|
}
|
} catch (Exception e) {
|
log.error("检查入库成功任务并完结AGV呼叫单异常", e);
|
}
|
}
|
|
/**
|
* 检查并修复异常状态的AGV任务:正在搬运但没有分配站点
|
* 这种情况可能是数据异常或并发问题导致的
|
*/
|
@Scheduled(cron = "0/30 * * * * ? ")
|
private void checkAbnormalTasksWithoutSite() {
|
if (!schedulerProperties.isEnabled()) {
|
return;
|
}
|
try {
|
// 查询状态为8(正在搬运)但没有分配站点的任务
|
List<Task> abnormalTasks = taskService.selectList(
|
new EntityWrapper<Task>()
|
.eq("task_type", "agv")
|
.eq("wrk_sts", 8L) // 正在搬运
|
.eq("is_deleted", 0) // 排除已删除的任务
|
.andNew()
|
.isNull("sta_no")
|
.or()
|
.eq("sta_no", "")
|
.or()
|
.eq("sta_no", "0")
|
);
|
|
if (abnormalTasks.isEmpty()) {
|
return;
|
}
|
|
log.warn("检测到{}个异常状态的AGV任务:正在搬运但没有分配站点,开始修复", abnormalTasks.size());
|
|
Date now = new Date();
|
int fixedCount = 0;
|
int completedCount = 0;
|
|
for (Task task : abnormalTasks) {
|
String displayTaskId = (task.getWrkNo() != null) ? String.valueOf(task.getWrkNo()) : String.valueOf(task.getId());
|
|
// 检查工作档和历史档状态
|
WrkMast wrkMast = null;
|
WrkMastLog wrkMastLog = null;
|
|
if (task.getWrkNo() != null) {
|
wrkMast = wrkMastService.selectOne(
|
new EntityWrapper<WrkMast>().eq("wrk_no", task.getWrkNo())
|
);
|
wrkMastLog = wrkMastLogService.selectOne(
|
new EntityWrapper<WrkMastLog>().eq("wrk_no", task.getWrkNo())
|
);
|
}
|
|
// 如果工作档已完成或已转历史档,直接结束任务
|
boolean shouldComplete = false;
|
String reason = "";
|
|
if (wrkMastLog != null) {
|
shouldComplete = true;
|
reason = "工作档已转历史档";
|
} else if (wrkMast != null) {
|
Long wrkSts = wrkMast.getWrkSts();
|
Integer ioType = task.getIoType();
|
|
if (wrkSts != null && ioType != null) {
|
// 入库任务:状态4或5
|
if ((ioType == 1 || ioType == 10 || ioType == 53 || ioType == 57) &&
|
(wrkSts == 4L || wrkSts == 5L)) {
|
shouldComplete = true;
|
reason = String.format("工作档已完成(入库),状态:%d", wrkSts);
|
}
|
// 出库任务:状态14或15
|
else if ((ioType == 101 || ioType == 110 || ioType == 103 || ioType == 107) &&
|
(wrkSts == 14L || wrkSts == 15L)) {
|
shouldComplete = true;
|
reason = String.format("工作档已完成(出库),状态:%d", wrkSts);
|
}
|
}
|
}
|
|
if (shouldComplete) {
|
// 工作档已完成,直接结束任务
|
task.setWrkSts(9L);
|
task.setModiTime(now);
|
if (taskService.updateById(task)) {
|
try {
|
agvHandler.moveTaskToHistory(Collections.singletonList(task));
|
completedCount++;
|
log.info("修复异常任务:{},{},已结束任务并转移到历史表,taskId:{}",
|
reason, displayTaskId, displayTaskId);
|
} catch (Exception e) {
|
log.error("修复异常任务:转移任务到历史表失败,taskId:{}", displayTaskId, e);
|
}
|
}
|
}/* else {
|
// 工作档未完成,尝试分配站点或重置状态
|
// 先尝试分配站点
|
String errorMsg = agvHandler.allocateSiteForTask(task);
|
if (errorMsg == null && task.getStaNo() != null && !task.getStaNo().isEmpty() && !task.getStaNo().equals("0")) {
|
// 分配站点成功
|
fixedCount++;
|
log.info("修复异常任务:已为任务分配站点,taskId:{},站点:{}", displayTaskId, task.getStaNo());
|
} else {
|
// 无法分配站点,重置状态为7(待呼叫AGV),等待下次分配
|
task.setWrkSts(7L);
|
task.setModiTime(now);
|
if (taskService.updateById(task)) {
|
fixedCount++;
|
log.warn("修复异常任务:无法分配站点,重置状态为7(待呼叫AGV),taskId:{},原因:{}",
|
displayTaskId, errorMsg != null ? errorMsg : "所有站点都被占用");
|
}
|
}
|
}*/
|
}
|
|
if (fixedCount > 0 || completedCount > 0) {
|
log.info("修复异常任务完成:修复了{}个任务,结束了{}个已完成工作档的任务", fixedCount, completedCount);
|
}
|
} catch (Exception e) {
|
log.error("检查并修复异常状态的AGV任务异常", e);
|
}
|
}
|
|
/**
|
* 检查AGV任务对应的工作档是否已完成或已转历史档并完结
|
* 处理被跳过的AGV任务:
|
* 1. 如果工作档已完成(wrk_sts=4,5,14,15),则完结AGV任务
|
* 2. 如果工作档进入历史档,立即结束AGV任务
|
* 3. 如果入库成功,也结束掉搬运任务(已在checkInboundCompletedTasks中实现)
|
*/
|
@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状态
|
.eq("is_deleted", 0) // 排除已删除的任务
|
);
|
|
if (agvTasks.isEmpty()) {
|
return;
|
}
|
|
Date now = new Date();
|
int completedCount = 0;
|
List<Task> completedTasks = new ArrayList<>();
|
|
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())
|
);
|
}
|
|
// 检查历史档是否存在(无论工作档是否存在都需要检查)
|
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); // 取第一个
|
}
|
}
|
|
// 如果工作档存在,检查是否已完成
|
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);
|
}
|
}
|
}
|
|
// 1. 如果工作档进入历史档,立即结束AGV任务(只要历史档存在就结束)
|
if (!isCompleted && wrkMastLog != null) {
|
isCompleted = true;
|
reason = String.format("工作档已转历史档,立即结束AGV任务,历史档状态:%d", wrkMastLog.getWrkSts());
|
}
|
|
// 如果已完成,更新AGV任务状态并收集到列表
|
if (isCompleted) {
|
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:{},站点:{}",
|
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表中
|
if (!completedTasks.isEmpty()) {
|
try {
|
agvHandler.moveTaskToHistory(completedTasks);
|
log.info("入库/出库完成,已将{}个AGV任务转移到历史表(不保留在Task表中)", completedTasks.size());
|
} catch (Exception e) {
|
log.error("入库/出库完成,转移AGV任务到历史表失败", e);
|
}
|
}
|
|
if (completedCount > 0) {
|
log.info("本次检查完结了{}个AGV呼叫单(工作档已完成或已转历史档)", completedCount);
|
}
|
} catch (Exception e) {
|
log.error("检查工作档已完成或历史档完结任务并完结AGV呼叫单异常", e);
|
}
|
}
|
|
/**
|
* 查询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; // 继续处理
|
}
|
}
|
|
}
|