自动化立体仓库 - WMS系统
chen.lin
2026-02-14 371462edc6b3ee1de97c235d4a019b544badda0d
src/main/java/com/zy/asrs/service/impl/TaskServiceImpl.java
@@ -1,12 +1,445 @@
package com.zy.asrs.service.impl;
import com.zy.asrs.mapper.TaskMapper;
import com.zy.asrs.entity.Task;
import com.zy.asrs.service.TaskService;
import com.baomidou.mybatisplus.mapper.EntityWrapper;
import com.baomidou.mybatisplus.service.impl.ServiceImpl;
import com.core.common.Cools;
import com.core.common.DateUtils;
import com.core.exception.CoolException;
import com.zy.asrs.entity.*;
import com.zy.asrs.mapper.TaskMapper;
import com.zy.asrs.service.*;
import com.zy.asrs.task.handler.AgvHandler;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.Date;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.TimeUnit;
@Slf4j
@Service("taskService")
public class TaskServiceImpl extends ServiceImpl<TaskMapper, Task> implements TaskService {
    @Autowired
    private TaskLogService taskLogService;
    @Autowired
    private LocCacheService locCacheService;
    @Autowired
    private WaitPakinService waitPakinService;
    @Autowired
    private TaskDetlService taskDetlService;
    @Autowired
    private TaskService taskService;
    @Autowired
    private TaskDetlLogService taskDetlLogService;
    @Autowired
    private OrderPakoutService orderPakoutService;
    @Autowired
    private OrderDetlPakoutService orderDetlPakoutService;
    @Autowired
    private AgvHandler agvHandler;
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void completeWrkMast(String workNo, Long userId) {
        Task wrkMast = this.selectOne(new EntityWrapper<Task>()
                .eq("wrk_no", workNo)
                .andNew("(is_deleted = 0)"));
        if (Cools.isEmpty(wrkMast)) {
            throw new CoolException(workNo + "工作档不存在");
        }
        if (wrkMast.getWrkSts() == 4 || wrkMast.getWrkSts() == 14) {
            throw new CoolException("当前工作档已完成");
        }
        // 入库 + 库位转移
        if (wrkMast.getIoType() < 50){
            wrkMast.setWrkSts(4L);
            // 出库
        } else  {
            wrkMast.setWrkSts(14L);
        }
        Date now = new Date();
        wrkMast.setCrnStrTime(DateUtils.calculate(now, 1L, TimeUnit.SECONDS, true));
        wrkMast.setCrnEndTime(now);
        wrkMast.setModiTime(now);
        wrkMast.setModiUser(userId);
        // 完成操作人员记录
        wrkMast.setManuType("手动完成");
        if (!this.updateById(wrkMast)) {
            throw new CoolException("修改工作档失败");
        }
    }
    @Override
    @Transactional
    public void pickWrkMast(String workNo, Long userId) {
        Task wrkMast = this.selectOne(new EntityWrapper<Task>()
                .eq("wrk_no", workNo)
                .andNew("(is_deleted = 0)"));
        if (Cools.isEmpty(wrkMast)) {
            throw new CoolException(workNo + "工作档不存在");
        }
        // 入出库类型判断
        if (wrkMast.getIoType() != 103 && wrkMast.getIoType() != 104 && wrkMast.getIoType() != 107) {
            throw new CoolException("当前入出库类型无法进行操作");
        }
        // 工作状态判断
        if (wrkMast.getWrkSts() < 11 || wrkMast.getWrkSts() == 15) {
            throw new CoolException("当前工作状态无法进行操作");
        }
        // 保存工作明细档历史档
//        if (!wrkDetlLogService.save(wrkMast.getWrkNo())) {
//            throw new CoolException("保存工作明细档历史档失败");
//        }
        // 保存工作主档历史档
        if (!taskLogService.save(wrkMast.getWrkNo())) {
            throw new CoolException("保存工作主档历史档失败");
        }
        // 获取目标站
//        Wrapper<StaDesc> wrapper = new EntityWrapper<StaDesc>()
//                .eq("type_no", wrkMast.getIoType() - 50)
//                .eq("stn_no", wrkMast.getStaNo()) // 作业站点 = 拣料出库的目标站
//                .eq("crn_no", wrkMast.getCrnNo()); // 堆垛机号
//        StaDesc staDesc = staDescService.selectOne(wrapper);
//        if (Cools.isEmpty(staDesc)) {
//            throw new CoolException("入库路径不存在");
//        }
        Date now = new Date();
        // 堆垛机站点(目标站)
//        Integer staNo = staDesc.getCrnStn();
        // 更新工作档数据状态
        wrkMast.setIoType(wrkMast.getIoType() - 50); // 入出库类型: 103->53,104->54,107->57
        wrkMast.setWrkSts(2L); // 工作状态: 2.设备上走
        wrkMast.setSourceStaNo(wrkMast.getStaNo()); // 源站
//        wrkMast.setStaNo(staNo + ""); // 目标站
        wrkMast.setLocNo(wrkMast.getSourceLocNo()); // 目标库位 = 出库时的源库位
        wrkMast.setSourceLocNo(""); // 源库位清空
        wrkMast.setModiTime(now);
        wrkMast.setModiUser(userId);
        if (!this.updateById(wrkMast)) {
            throw new CoolException("更新工作档数据状态失败");
        }
        // 修改库位状态 Q.拣料/盘点/并板再入库
        LocCache locMast = locCacheService.selectOne(new EntityWrapper<LocCache>().eq("loc_no", wrkMast.getLocNo()));
        locMast.setLocSts("Q");
        locMast.setModiTime(now);
        locMast.setModiUser(userId);
        if (!locCacheService.updateById(locMast)) {
            throw new CoolException("修改库位状态失败");
        }
    }
    @Override
    public List<Task> selectToBeCompleteData() {
        return this.baseMapper.selectToBeCompleteData();
    }
    @Override
    @Transactional
    public void cancelWrkMast(String workNo, Long userId) {
        Date now = new Date();
        Task wrkMast = this.selectOne(new EntityWrapper<Task>()
                .eq("wrk_no", workNo)
                .andNew("(is_deleted = 0)"));
        if (Cools.isEmpty(wrkMast)) {
            throw new CoolException(workNo + "工作档不存在");
        }
        // 如果是AGV任务,根据任务状态决定是否需要调用AGV接口取消任务
        // 仅状态7(新建AGV任务)不访问AGV直接取消;其他状态必须先调用AGV取消接口,AGV返回成功才能取消
        if ("agv".equals(wrkMast.getTaskType())) {
            Long wrkSts = wrkMast.getWrkSts();
            if (wrkSts != null && wrkSts == 7L) {
                // 状态7:新建AGV任务,未发送给AGV,无需调用AGV接口,直接取消
                String displayTaskId = (wrkMast.getWrkNo() != null) ? String.valueOf(wrkMast.getWrkNo()) : String.valueOf(wrkMast.getId());
                log.info("取消AGV任务:任务ID:{},状态:7(新建AGV任务),无需调用AGV接口,直接取消", displayTaskId);
            } else {
                // 非状态7(含8、9、10等):必须先调用AGV取消接口,AGV返回成功才能取消
                if (wrkMast.getId() == null) {
                    throw new CoolException("取消AGV任务失败:任务ID为空");
                }
                String agvWrkNo = wrkMast.getAgvWrkNo();
                Integer wrkNo = wrkMast.getWrkNo();
                Long taskId = wrkMast.getId();
                if ((agvWrkNo == null || agvWrkNo.isEmpty()) && wrkNo == null && taskId == null) {
                    throw new CoolException("取消AGV任务失败:无法获取有效的任务标识(agvWrkNo、wrkNo和id都为空)");
                }
                String errorMsg = agvHandler.cancelAgvTask(wrkMast);
                if (errorMsg != null) {
                    log.warn("取消AGV任务失败,AGV未返回成功 - 任务ID:{},错误:{}",
                            (wrkMast.getWrkNo() != null) ? String.valueOf(wrkMast.getWrkNo()) : String.valueOf(wrkMast.getId()), errorMsg);
                    throw new CoolException("取消AGV任务失败:" + errorMsg);
                }
            }
        }
        String locNo = ""; // 待修改目标库位
        String locSts = ""; // 待修改目标库位状态
        // 入库取消(修改目标库位)
        if (wrkMast.getIoType() < 100) {
            locNo = wrkMast.getLocNo();
            locSts = "O";
            // 库位转移
            if (wrkMast.getIoType() == 11) {
                // 库位转移:源库位
                LocCache locMast = locCacheService.selectOne(new EntityWrapper<LocCache>().eq("loc_no", wrkMast.getSourceLocNo()));
                if (Cools.isEmpty(locMast)) {
                    throw new CoolException("取消库位转移失败,源库位不存在:" + wrkMast.getSourceLocNo());
                }
                locMast.setLocSts(wrkMast.getFullPlt().equalsIgnoreCase("N") ? "D" : "F");
                locMast.setModiTime(now);
                locMast.setModiUser(userId);
                locCacheService.updateById(locMast);
            }
            // 出库取消(修改源库位)
        } else {
            locNo = wrkMast.getSourceLocNo();
            // 出库 ===>> F.在库
            if (wrkMast.getIoType() > 100 && wrkMast.getIoType() != 110) {
                locSts = "F";
                // 空板出库 ===>> D.空桶/空栈板
            } else if (wrkMast.getIoType() == 110) {
                locSts = "D";
                // 库位转移 ===>> D.空桶/空栈板
            } else if (wrkMast.getIoType() == 11) {
                locSts = wrkMast.getFullPlt().equalsIgnoreCase("N") ? "D" : "F";
                // 库位转移:目标库位
                LocCache locMast = locCacheService.selectOne(new EntityWrapper<LocCache>().eq("loc_no", wrkMast.getLocNo()));
                if (Cools.isEmpty(locMast)) {
                    throw new CoolException("取消库位转移失败,目标库位不存在:" + wrkMast.getSourceLocNo());
                }
                locMast.setLocSts("O");
                locMast.setModiTime(now);
                locMast.setModiUser(userId);
                locCacheService.updateById(locMast);
            }
        }
        //取消入库工作档时,查询组托表,如果有将状态改为待处理
        if (wrkMast.getIoType() == 1) {
            List<WaitPakin> waitPakins = waitPakinService.selectList(new EntityWrapper<WaitPakin>().eq("zpallet", wrkMast.getBarcode()));
            for (WaitPakin waitPakin : waitPakins) {
                if (!Cools.isEmpty(waitPakin)) {
                    waitPakin.setIoStatus("N");
                    waitPakin.setLocNo("");
                    waitPakinService.update(waitPakin, new EntityWrapper<WaitPakin>()
//                            .eq("order_no", waitPakin.getOrderNo())
                            .eq("zpallet", waitPakin.getZpallet())
                            .eq("matnr", waitPakin.getMatnr())
                            .eq("batch", waitPakin.getBatch()));
                }
            }
        }
        // 取消操作人员记录
        wrkMast.setManuType("手动取消");
        wrkMast.setModiUser(userId);
        wrkMast.setModiTime(now);
        if (!taskService.updateById(wrkMast)) {
            throw new CoolException("取消工作档失败");
        }
        // 保存工作主档历史档
        if (!taskLogService.save(wrkMast.getWrkNo())) {
            throw new CoolException("保存工作历史档失败, workNo = " + wrkMast.getWrkNo());
        }
        // 逻辑删除工作主档
        wrkMast.setIsDeleted(1);
        boolean wrkMastRes = taskService.updateById(wrkMast);
        if (wrkMast.getIoType() != 10 && wrkMast.getIoType() != 110) {
            // 删除工作档明细
            boolean wrkDetlRes = taskDetlService.delete(new EntityWrapper<TaskDetl>().eq("wrk_no", workNo));
        }
        // 修改库位状态(如果库位不为空)
        boolean locMastRes = true;
        if (!Cools.isEmpty(locNo)&&wrkMast.getIoType() > 100) {
            LocCache locMast = locCacheService.selectOne(new EntityWrapper<LocCache>().eq("loc_no", locNo));
            if (Cools.isEmpty(locMast)) {
                throw new CoolException("取消工作档失败,库位不存在:" + locNo);
            }
            if (!Cools.isEmpty(locSts)) {
                locMast.setLocSts(locSts);
                locMast.setModiTime(now);
                locMast.setModiUser(userId);
                locMastRes = locCacheService.updateById(locMast);
            }
        }
        if (!wrkMastRes || !locMastRes) {
            throw new CoolException("保存数据失败");
        }
    }
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteWrkMast(String workNo, Long userId) {
        Date now = new Date();
        Task wrkMast = this.selectOne(new EntityWrapper<Task>()
                .eq("wrk_no", workNo)
                .andNew("(is_deleted = 0)"));
        if (Cools.isEmpty(wrkMast)) {
            throw new CoolException(workNo + "工作档不存在");
        }
        String displayTaskId = (wrkMast.getWrkNo() != null) ? String.valueOf(wrkMast.getWrkNo()) : String.valueOf(wrkMast.getId());
        // 如果是AGV任务,尝试同步申请AGV取消(但不会被AGV返回的错误校验拦截,会继续删除)
        if ("agv".equals(wrkMast.getTaskType())) {
            Long wrkSts = wrkMast.getWrkSts();
            // 状态8和9:已发送给AGV任务,尝试调用AGV接口取消任务
            // 状态10:AGV呼叫异常,可以取消,但不会请求AGV取消接口
            // 状态7或更早:还未发送给AGV,无需调用AGV接口
            if (wrkSts != null && wrkSts >= 8L && wrkSts != 10L) {
                try {
                    // 验证任务信息是否完整
                    if (wrkMast.getId() != null) {
                        // 验证taskId是否可用(agvWrkNo、wrkNo或id至少有一个)
                        String agvWrkNo = wrkMast.getAgvWrkNo();
                        Integer wrkNo = wrkMast.getWrkNo();
                        Long taskId = wrkMast.getId();
                        if ((agvWrkNo != null && !agvWrkNo.isEmpty()) || wrkNo != null || taskId != null) {
                            // 同步申请AGV取消,但不抛出异常(不会被错误校验拦截)
                            String errorMsg = agvHandler.cancelAgvTask(wrkMast);
                            if (errorMsg != null) {
                                log.warn("删除AGV任务:尝试取消AGV任务失败,但继续执行删除操作,任务ID:{},错误:{}", displayTaskId, errorMsg);
                            } else {
                                log.info("删除AGV任务:成功取消AGV任务,任务ID:{}", displayTaskId);
                            }
                        } else {
                            log.warn("删除AGV任务:无法获取有效的任务标识(agvWrkNo、wrkNo和id都为空),跳过AGV取消,继续执行删除操作,任务ID:{}", displayTaskId);
                        }
                    } else {
                        log.warn("删除AGV任务:任务ID为空,跳过AGV取消,继续执行删除操作,任务ID:{}", displayTaskId);
                    }
                } catch (Exception e) {
                    // 捕获所有异常,记录日志但不阻止删除操作(不会被AGV返回的错误校验拦截)
                    log.error("删除AGV任务:尝试取消AGV任务时发生异常,但继续执行删除操作,任务ID:{}", displayTaskId, e);
                }
            } else {
                // 状态10(AGV呼叫异常)或状态7或更早,无需调用AGV接口
                if (wrkSts != null && wrkSts == 10L) {
                    log.info("删除AGV任务:任务ID:{},状态:{}(AGV呼叫异常),无需调用AGV接口,直接删除", displayTaskId, wrkSts);
                } else {
                    log.info("删除AGV任务:任务ID:{},状态:{}(待呼叫AGV或更早),无需调用AGV接口,直接删除", displayTaskId, wrkSts);
                }
            }
        }
        // 释放库位等资源(类似cancelWrkMast的逻辑)
        String locNo = ""; // 待修改目标库位
        String locSts = ""; // 待修改目标库位状态
        // 入库取消(修改目标库位)
        if (wrkMast.getIoType() < 100) {
            locNo = wrkMast.getLocNo();
            locSts = "O";
            // 库位转移
            if (wrkMast.getIoType() == 11) {
                // 库位转移:源库位
                LocCache locMast = locCacheService.selectOne(new EntityWrapper<LocCache>().eq("loc_no", wrkMast.getSourceLocNo()));
                if (!Cools.isEmpty(locMast)) {
                    locMast.setLocSts(wrkMast.getFullPlt().equalsIgnoreCase("N") ? "D" : "F");
                    locMast.setModiTime(now);
                    locMast.setModiUser(userId);
                    locCacheService.updateById(locMast);
                }
            }
            // 出库取消(修改源库位)
        } else {
            locNo = wrkMast.getSourceLocNo();
            // 出库 ===>> F.在库
            if (wrkMast.getIoType() > 100 && wrkMast.getIoType() != 110) {
                locSts = "F";
                // 空板出库 ===>> D.空桶/空栈板
            } else if (wrkMast.getIoType() == 110) {
                locSts = "D";
                // 库位转移 ===>> D.空桶/空栈板
            } else if (wrkMast.getIoType() == 11) {
                locSts = wrkMast.getFullPlt().equalsIgnoreCase("N") ? "D" : "F";
                // 库位转移:目标库位
                LocCache locMast = locCacheService.selectOne(new EntityWrapper<LocCache>().eq("loc_no", wrkMast.getLocNo()));
                if (!Cools.isEmpty(locMast)) {
                    locMast.setLocSts("O");
                    locMast.setModiTime(now);
                    locMast.setModiUser(userId);
                    locCacheService.updateById(locMast);
                }
            }
        }
        //取消入库工作档时,查询组托表,如果有将状态改为待处理
        if (wrkMast.getIoType() == 1) {
            List<WaitPakin> waitPakins = waitPakinService.selectList(new EntityWrapper<WaitPakin>().eq("zpallet", wrkMast.getBarcode()));
            for (WaitPakin waitPakin : waitPakins) {
                if (!Cools.isEmpty(waitPakin)) {
                    waitPakin.setIoStatus("N");
                    waitPakin.setLocNo("");
                    waitPakinService.update(waitPakin, new EntityWrapper<WaitPakin>()
                            .eq("zpallet", waitPakin.getZpallet())
                            .eq("matnr", waitPakin.getMatnr())
                            .eq("batch", waitPakin.getBatch()));
                }
            }
        }
        // 删除操作人员记录
        wrkMast.setManuType("手动删除");
        wrkMast.setModiUser(userId);
        wrkMast.setModiTime(now);
        // 逻辑删除工作主档
        wrkMast.setIsDeleted(1);
        if (!taskService.updateById(wrkMast)) {
            throw new CoolException("删除工作档失败");
        }
        if (wrkMast.getIoType() != 10 && wrkMast.getIoType() != 110) {
            // 删除工作档明细
            taskDetlService.delete(new EntityWrapper<TaskDetl>().eq("wrk_no", workNo));
        }
        // 修改库位状态(如果库位不为空)
        if (!Cools.isEmpty(locNo) && wrkMast.getIoType() > 100) {
            LocCache locMast = locCacheService.selectOne(new EntityWrapper<LocCache>().eq("loc_no", locNo));
            if (!Cools.isEmpty(locMast) && !Cools.isEmpty(locSts)) {
                locMast.setLocSts(locSts);
                locMast.setModiTime(now);
                locMast.setModiUser(userId);
                locCacheService.updateById(locMast);
            }
        }
        // 如果是入库任务,释放预约库位
        if (wrkMast.getIoType() != null && wrkMast.getIoType() < 100 && !Cools.isEmpty(wrkMast.getLocNo())) {
            try {
                LocCache locCache = locCacheService.selectOne(
                        new EntityWrapper<LocCache>().eq("loc_no", wrkMast.getLocNo())
                );
                if (locCache != null && "S".equals(locCache.getLocSts())) {
                    // 库位状态为S(入库预约),释放为O(闲置)
                    locCache.setLocSts("O");
                    locCache.setModiTime(now);
                    locCache.setModiUser(userId);
                    locCacheService.updateById(locCache);
                    log.info("删除AGV任务:已释放预约库位:{}(S→O),任务ID:{}", wrkMast.getLocNo(), displayTaskId);
                }
            } catch (Exception e) {
                log.warn("删除AGV任务:释放预约库位失败,库位:{},任务ID:{}", wrkMast.getLocNo(), displayTaskId, e);
            }
        }
        log.info("删除AGV任务成功:任务ID:{},工作号:{}", displayTaskId, workNo);
    }
    @Override
    public List<Task> selectToBeHistoryData() {
        return this.baseMapper.selectToBeHistoryData();
    }
}