自动化立体仓库 - WMS系统
chen.llin
3 天以前 cea1758e1f540e3f5f807951f128b7385b32afe6
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,10 +23,15 @@
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
@@ -55,23 +64,175 @@
    private SchedulerProperties schedulerProperties;
    /**
     * 呼叫agv搬运
     * 记录上次处理的任务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;
        }
        // 查询待呼叫agv任务,按id升序排序(id最小的优先呼叫)
        List<Task> taskList = taskService.selectList(
            new EntityWrapper<Task>()
                .eq("wrk_sts", 7)
                .orderBy("id", true) // 按id升序,id最小的优先
        );
        if(taskList.isEmpty()) {
        if (!iscallAgv.compareAndSet(false, true)) {
            log.debug("呼叫AGV定时任务:上一次分配站点任务还在执行中,跳过本次执行");
            return;
        }
        agvHandler.callAgv(taskList);
        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);
        }
    }
    /**
@@ -85,22 +246,22 @@
        // 获取呼叫agv配置
        List<Config> configs = configService.selectList(new EntityWrapper<Config>().in("code", "eastCallAgvControl", "westCallAgvControl").eq("status", 1));
        if(configs.isEmpty()) {
        if (configs.isEmpty()) {
            return;
        }
        // 获取agv出库可用站点
        List<String> sites = new ArrayList<>();
        for(Config config: configs) {
        for (Config config : configs) {
            String value = config.getValue();
            if(Cools.isEmpty(value)) {
            if (Cools.isEmpty(value)) {
                continue;
            }
            String[] split = value.split(";");
            sites.addAll(Arrays.asList(split));
        }
        if(sites.isEmpty()) {
        if (sites.isEmpty()) {
            return;
        }
@@ -115,8 +276,8 @@
        if (!schedulerProperties.isEnabled()) {
            return;
        }
        List<Task> taskList = taskService.selectList(new EntityWrapper<Task>().eq("wrk_sts", 9));
        if(taskList.isEmpty()) {
        List<Task> taskList = taskService.selectList(new EntityWrapper<Task>().eq("wrk_sts", 9).eq("is_deleted", 0));
        if (taskList.isEmpty()) {
            return;
        }
        agvHandler.moveTaskToHistory(taskList);
@@ -134,55 +295,61 @@
        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")
                    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("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("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)) {
                    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:{}",
                                agvTask.getId(), wrkMast.getWrkNo(), wrkMast.getBarcode());
                            log.info("入库任务工作档已入库成功,完结AGV呼叫单,taskId:{},wrkNo:{},barcode:{}",
                                    displayTaskId, wrkMast.getWrkNo(), wrkMast.getBarcode());
                        }
                    }
                }
            }
            // 立即将完成的AGV任务转移到历史表,不保留在Task表中
            if (!completedTasks.isEmpty()) {
                try {
@@ -192,7 +359,7 @@
                    log.error("入库完成,转移AGV任务到历史表失败", e);
                }
            }
            if (completedCount > 0) {
                log.info("本次检查完结了{}个入库AGV呼叫单", completedCount);
            }
@@ -202,8 +369,131 @@
    }
    /**
     * 检查并修复异常状态的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任务:如果工作档已完成(wrk_sts=4,5,14,15)或已转历史档并完结,则完结AGV任务
     * 处理被跳过的AGV任务:
     * 1. 如果工作档已完成(wrk_sts=4,5,14,15),则完结AGV任务
     * 2. 如果工作档进入历史档,立即结束AGV任务
     * 3. 如果入库成功,也结束掉搬运任务(已在checkInboundCompletedTasks中实现)
     */
    @Scheduled(cron = "0/10 * * * * ? ")
    private void checkCompletedTasksInHistory() {
@@ -213,94 +503,77 @@
        try {
            // 查询状态为8(已呼叫AGV)的AGV任务
            List<Task> agvTasks = taskService.selectList(
                new EntityWrapper<Task>()
                    .eq("task_type", "agv")
                    .eq("wrk_sts", 8L)  // 已呼叫AGV状态
                    .isNotNull("wrk_no")
                    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())
                            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)) {
                                (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)) {
                                (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);
                            }
                        }
                    }
                }
                // 1. 如果工作档进入历史档,立即结束AGV任务(只要历史档存在就结束)
                if (!isCompleted && wrkMastLog != null) {
                    isCompleted = true;
                    reason = String.format("工作档已转历史档,立即结束AGV任务,历史档状态:%d", wrkMastLog.getWrkSts());
                }
                // 如果已完成,更新AGV任务状态并收集到列表
                if (isCompleted) {
                    agvTask.setWrkSts(9L);
@@ -308,12 +581,44 @@
                    if (taskService.updateById(agvTask)) {
                        completedTasks.add(agvTask);
                        completedCount++;
                        log.info("{},完结AGV呼叫单,taskId:{},wrkNo:{},barcode:{},站点:{}",
                            reason, agvTask.getId(), agvTask.getWrkNo(), agvTask.getBarcode(), agvTask.getStaNo());
                        // 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 {
@@ -323,7 +628,7 @@
                    log.error("入库/出库完成,转移AGV任务到历史表失败", e);
                }
            }
            if (completedCount > 0) {
                log.info("本次检查完结了{}个AGV呼叫单(工作档已完成或已转历史档)", completedCount);
            }
@@ -332,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; // 继续处理
        }
    }
}