自动化立体仓库 - WMS系统
chen.llin
5 天以前 74951023b54f1789d1244fe923219d467487d771
agv增加一个新单号防重复  ,增加一个手动呼叫agv
9个文件已修改
1个文件已添加
254 ■■■■ 已修改文件
src/main/java/com/zy/asrs/entity/Task.java 7 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/asrs/service/impl/MobileServiceImpl.java 17 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/asrs/service/impl/OpenServiceImpl.java 58 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/asrs/task/AgvScheduler.java 24 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/asrs/task/handler/AgvHandler.java 37 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/common/constant/ApiInterfaceConstant.java 4 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/common/utils/AgvUtils.java 26 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/common/web/WcsController.java 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/webapp/static/js/task/task.js 74 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/webapp/views/task/task.html 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/asrs/entity/Task.java
@@ -348,6 +348,13 @@
    @TableField("is_deleted")
    private Integer isDeleted;
    /**
     * AGV工作号(格式:T+wrk_no+年月日时分秒)
     */
    @ApiModelProperty(value = "AGV工作号(格式:T+wrk_no+年月日时分秒)")
    @TableField("agv_wrk_no")
    private String agvWrkNo;
    public Task() {
    }
src/main/java/com/zy/asrs/service/impl/MobileServiceImpl.java
@@ -25,6 +25,7 @@
import com.zy.common.model.enums.WorkNoType;
import com.zy.common.properties.AgvProperties;
import com.zy.common.service.CommonService;
import com.zy.common.utils.AgvUtils;
import com.zy.common.utils.HttpHandler;
import lombok.extern.slf4j.Slf4j;
import org.apache.poi.ss.formula.functions.T;
@@ -253,10 +254,13 @@
        // 获取工作号
        int workNo = commonService.getWorkNo(WorkNoType.PICK.type);
        // 生成AGV工作号
        String agvWrkNo = AgvUtils.generateAgvWrkNo(workNo);
        // 保存工作档
        Task task = new Task();
        Date now = new Date();
        task.setWrkNo(workNo)
                .setAgvWrkNo(agvWrkNo) // 设置AGV工作号
                .setIoTime(now)
                .setWrkSts(7L) // 工作状态:11.生成出库ID
                .setIoType(ioType) // 入出库状态: 1.入库
@@ -1441,9 +1445,12 @@
    public void generateOutTask(BasStation station, LocCache loc, Long userId) {
        // 获取工作号
        int workNo = commonService.getWorkNo(WorkNoType.PICK.type);
        // 生成AGV工作号
        String agvWrkNo = AgvUtils.generateAgvWrkNo(workNo);
        // 保存工作档
        Task task = new Task();
        task.setWrkNo(workNo)
                .setAgvWrkNo(agvWrkNo)
                .setIoTime(new Date())
                .setWrkSts(11L) // 工作状态:11.生成出库ID
                .setIoType(101) // 入出库状态: 11.库格移载
@@ -1528,10 +1535,14 @@
        }
        // 获取工作号
        int workNo = commonService.getWorkNo(WorkNoType.PICK.type);
        // 生成AGV工作号
        String agvWrkNo = AgvUtils.generateAgvWrkNo(workNo);
        // 保存工作档
        Task task = new Task();
        Date now = new Date();
        task.setWrkNo(workNo)
                .setIoTime(new Date())
                .setAgvWrkNo(agvWrkNo) // 设置AGV工作号
                .setIoTime(now)
                .setWrkSts(1L) // 工作状态:11.生成出库ID
                .setIoType(1) // 入出库状态: 11.库格移载
                .setTaskType("agv")
@@ -1545,9 +1556,9 @@
                .setBarcode(barcode)// 托盘码
                .setLinkMis("N")
                .setAppeUser(userId)
                .setAppeTime(new Date())
                .setAppeTime(now)
                .setModiUser(userId)
                .setModiTime(new Date());
                .setModiTime(now);
        if (!taskService.insert(task)) {
            throw new CoolException("保存工作档失败");
        }
src/main/java/com/zy/asrs/service/impl/OpenServiceImpl.java
@@ -73,59 +73,21 @@
            return R.error("任务id不能为空");
        }
        
        log.info("收到AGV任务回调请求,taskId:{},fromBin:{},toBin:{},robotGroup:{},kind:{}",
            taskId, param.getFromBin(), param.getToBin(),
            Cools.isEmpty(param.getRobotGroup()) ? param.getRobotName() : param.getRobotGroup(),
        log.info("收到AGV任务回调请求,taskId:{},fromBin:{},toBin:{},robotGroup:{},kind:{}",
            taskId, param.getFromBin(), param.getToBin(),
            Cools.isEmpty(param.getRobotGroup()) ? param.getRobotName() : param.getRobotGroup(),
            param.getKind());
        
        // 根据taskId查询任务
        // taskId格式:T + 工作号(如"T5299")或 T + 任务ID(向后兼容)
        Task task = null;
        try {
            // 处理"T"前缀格式(如"T5299"或"T130")
            String numericId = taskId;
            if (taskId.startsWith("T") && taskId.length() > 1) {
                numericId = taskId.substring(1);
                    log.debug("检测到T前缀格式的taskId,提取数字:{}", numericId);
            }
            // 先尝试通过工作号(wrk_no)查询(优先,因为现在使用工作号作为taskId)
            try {
                Integer wrkNo = Integer.parseInt(numericId);
                task = taskService.selectOne(
                    new EntityWrapper<Task>().eq("wrk_no", wrkNo).eq("is_deleted", 0)
                );
                if (task != null) {
                    log.debug("通过工作号(wrk_no={})找到任务,taskId:{}", wrkNo, task.getId());
                }
            } catch (NumberFormatException e) {
                log.debug("无法解析为工作号,taskId:{}", taskId);
            }
            // 如果通过工作号没找到,尝试通过任务ID查询(向后兼容)
            if (task == null) {
                try {
                    Long taskIdLong = Long.parseLong(numericId);
                    task = taskService.selectById(taskIdLong);
                    if (task != null) {
                        log.debug("通过任务ID(id={})找到任务,taskId:{}", taskIdLong, taskId);
                    }
                } catch (NumberFormatException e) {
                    log.debug("无法解析为任务ID,taskId:{}", taskId);
                }
            }
        } catch (Exception e) {
            log.debug("解析taskId异常,taskId:{},异常:{}", taskId, e.getMessage());
        // 优先通过agvWrkNo字段查询(新格式:T+wrk_no+年月日时分秒)
        task = taskService.selectOne(
            new EntityWrapper<Task>().eq("agv_wrk_no", taskId).eq("is_deleted", 0)
        );
        if (task != null) {
            log.debug("通过agvWrkNo(agv_wrk_no={})找到任务,taskId:{}", taskId, task.getId());
        }
        // 如果还是没找到,尝试通过其他字段查询(如sheetNo等,向后兼容)
        if (task == null) {
            log.debug("通过工作号和任务ID都没找到,尝试通过其他字段查询,taskId:{}", taskId);
            task = taskService.selectOne(
                new EntityWrapper<Task>().eq("sheet_no", taskId).eq("is_deleted", 0)
            );
        }
        if (task == null) {
            log.warn("未找到对应的任务,taskId:{}", taskId);
            return R.error("任务不存在,taskId:" + taskId);
src/main/java/com/zy/asrs/task/AgvScheduler.java
@@ -645,17 +645,19 @@
     */
    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;
            // 构建订单ID,优先使用agvWrkNo,如果为空则使用T+wrkNo(向后兼容)
            String orderId = agvTask.getAgvWrkNo();
            if (orderId == null || orderId.isEmpty()) {
                if (agvTask.getWrkNo() != null) {
                    orderId = "T" + agvTask.getWrkNo();
                } else {
                    String errorMsg = String.format("查询AGV订单状态失败:任务ID:%s,agvWrkNo和wrkNo都为空", displayTaskId);
                    log.warn("查询AGV订单状态失败 - 任务ID:{},{}", displayTaskId, errorMsg);
                    agvTask.setErrorMemo2(errorMsg);
                    agvTask.setErrorTime2(new Date());
                    taskService.updateById(agvTask);
                    return null;
                }
            }
            // 构建请求JSON
src/main/java/com/zy/asrs/task/handler/AgvHandler.java
@@ -21,6 +21,7 @@
import com.zy.asrs.entity.WrkMastLog;
import com.zy.common.constant.ApiInterfaceConstant;
import com.zy.common.properties.AgvProperties;
import com.zy.common.utils.AgvUtils;
import com.zy.common.utils.HttpHandler;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
@@ -669,14 +670,26 @@
        return result;
    }
    /**
     * 构造请求内容(仙工M4格式)
     */
    public String getRequest(Task task, String nameSpace) {
        JSONObject object = new JSONObject();
        // taskId使用工作号(wrk_no),格式:T + 工作号
        // 如果工作号为空,则使用任务ID作为备选
        String taskIdValue = (task.getWrkNo() != null) ? "T" + task.getWrkNo() : "T" + task.getId();
        // taskId使用agvWrkNo字段,如果为空则生成新的agvWrkNo
        String taskIdValue = task.getAgvWrkNo();
        if (taskIdValue == null || taskIdValue.isEmpty()) {
            // 如果agvWrkNo为空,生成新的agvWrkNo
            if (task.getWrkNo() != null) {
                taskIdValue = AgvUtils.generateAgvWrkNo(task.getWrkNo());
                // 更新任务的agvWrkNo字段
                task.setAgvWrkNo(taskIdValue);
                taskService.updateById(task);
            } else {
                // 如果工作号也为空,使用任务ID作为备选(向后兼容)
                taskIdValue = "T" + task.getId();
            }
        }
        object.put("taskId", taskIdValue);
        // fromBin使用源库位编号(sourceLocNo),如果为空则使用源站点编号(sourceStaNo)作为备选
        String fromBin = task.getSourceLocNo();
@@ -1042,8 +1055,12 @@
            // todo 计算agv目标暂存位
            int endSite = 2004;
            // 生成AGV工作号
            String agvWrkNo = AgvUtils.generateAgvWrkNo(wrkMast.getWrkNo());
            // 插入agv任务
            Task task = new Task(wrkMast.getWrkNo(), 7L, wrkMast.getIoType(), String.valueOf(wrkMast.getStaNo()), String.valueOf(endSite), null, wrkMast.getBarcode());
            task.setAgvWrkNo(agvWrkNo); // 设置AGV工作号
            taskService.insert(task);
            // 更新任务档agv搬运标识
            wrkMast.setCallAgv(2);
@@ -1102,10 +1119,16 @@
        // 构造取消任务请求
        JSONObject cancelRequest = new JSONObject();
        // taskId使用工作号(wrk_no),格式:T + 工作号
        // 如果工作号为空,则使用任务ID作为备选
        String taskIdValue = (task.getWrkNo() != null) ? "T" + task.getWrkNo() : "T" + task.getId();
        cancelRequest.put("taskId", taskIdValue);
        // taskId使用agvWrkNo字段,如果为空则使用工作号或任务ID作为备选
        String taskIdValue = task.getAgvWrkNo();
        if (taskIdValue == null || taskIdValue.isEmpty()) {
            if (task.getWrkNo() != null) {
                taskIdValue = AgvUtils.generateAgvWrkNo(task.getWrkNo());
            } else {
                taskIdValue = "T" + task.getId();
            }
        }
        cancelRequest.put("taskId", task.getAgvWrkNo());
        cancelRequest.put("kind", kind);
        String body = cancelRequest.toJSONString();
src/main/java/com/zy/common/constant/ApiInterfaceConstant.java
@@ -46,10 +46,8 @@
     */
    public static final String AGV_CANCEL_TASK_PATH = "/api/agv/cancelTransport";
    /* ***************************************Falcon接口对接 start*******************************************************/
    /**
     * agv - 查询订单状态
     * 仙工M4 - 查询订单状态
     */
    public static final String AGV_FIND_ONE_PATH = "/api/entity/find/one";
src/main/java/com/zy/common/utils/AgvUtils.java
New file
@@ -0,0 +1,26 @@
package com.zy.common.utils;
import java.text.SimpleDateFormat;
import java.util.Date;
/**
 * AGV工具类
 * @author chen.lin
 * @description AGV相关工具方法
 * @createDate 2026/01/25
 */
public class AgvUtils {
    /**
     * 生成AGV工作号(格式:T+wrk_no+yyyyMMddHHmmss)
     * @param wrkNo 工作号
     * @return AGV工作号
     */
    public static String generateAgvWrkNo(Integer wrkNo) {
        if (wrkNo == null) {
            return null;
        }
        SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmss");
        return "T" + wrkNo + sdf.format(new Date());
    }
}
src/main/java/com/zy/common/web/WcsController.java
@@ -17,6 +17,7 @@
import com.zy.common.model.StartupDto;
import com.zy.common.model.enums.WorkNoType;
import com.zy.common.service.CommonService;
import com.zy.common.utils.AgvUtils;
import com.zy.common.web.param.GenerateAgvTaskParam;
import com.zy.common.web.param.SearchLocParam;
import lombok.extern.slf4j.Slf4j;
@@ -103,10 +104,13 @@
        // 获取工作号
        int workNo = commonService.getWorkNo(WorkNoType.PICK.type);
        // 生成AGV工作号
        String agvWrkNo = AgvUtils.generateAgvWrkNo(workNo);
        // 保存工作档
        Task task = new Task();
        Date now = new Date();
        task.setWrkNo(workNo)
                .setAgvWrkNo(agvWrkNo) // 设置AGV工作号
                .setIoTime(now)
                .setWrkSts(7L) // 工作状态:11.生成出库ID
                .setIoType(1) // 入出库状态: 1.入库
src/main/webapp/static/js/task/task.js
@@ -38,7 +38,7 @@
            , {field: 'takeNone', align: 'center', title: '空操作', hide: true}
            , {field: 'modiUser$', align: 'center', title: '修改人员', hide: true}
            , {field: 'modiTime$', align: 'center', title: '修改时间', hide: true, width: 160}
            , {fixed: 'right', title: '操作', align: 'center', toolbar: '#operate', width: 200}
            , {fixed: 'right', title: '操作', align: 'center', toolbar: '#operate', width: 250}
        ]],
        request: {
            pageName: 'curr',
@@ -221,6 +221,10 @@
                }, function () {
                });
                break;
            //  呼叫AGV
            case 'callAgv':
                callAgvMove(data);
                break;
        }
    });
@@ -318,6 +322,74 @@
    layDateRender();
    // 呼叫AGV搬运
    function callAgvMove(data) {
        var defaultOrgSite = data.sourceStaNo || '';
        var defaultTarSite = data.staNo || '';
        var defaultBarcode = data.barcode || '';
        layer.open({
            type: 1,
            title: '呼叫AGV搬运 - 工作号:' + data.wrkNo,
            area: ['450px', '400px'],
            shadeClose: true,
            content: '<form class="layui-form" style="padding: 20px;">' +
                     '<div class="layui-form-item">' +
                     '<label class="layui-form-label"><span style="color: red;">*</span>源站点:</label>' +
                     '<div class="layui-input-block">' +
                     '<input type="text" name="orgSite" value="' + defaultOrgSite + '" placeholder="请输入源站点" class="layui-input" lay-verify="required">' +
                     '</div></div>' +
                     '<div class="layui-form-item">' +
                     '<label class="layui-form-label"><span style="color: red;">*</span>目标站点:</label>' +
                     '<div class="layui-input-block">' +
                     '<input type="text" name="tarSite" value="' + defaultTarSite + '" placeholder="请输入目标站点" class="layui-input" lay-verify="required">' +
                     '</div></div>' +
                     '<div class="layui-form-item">' +
                     '<label class="layui-form-label"><span style="color: red;">*</span>托盘码:</label>' +
                     '<div class="layui-input-block">' +
                     '<input type="text" name="barcode" value="' + defaultBarcode + '" placeholder="请输入托盘码" class="layui-input" lay-verify="required">' +
                     '</div></div>' +
                     '<div class="layui-form-item" style="text-align: center; margin-top: 30px;">' +
                     '<button class="layui-btn" lay-submit lay-filter="callAgvSubmit">确认呼叫</button>' +
                     '<button type="button" class="layui-btn layui-btn-primary" onclick="layer.closeAll()">取消</button>' +
                     '</div></form>',
            success: function(layero, index) {
                form.render();
                form.on('submit(callAgvSubmit)', function(formData) {
                    var loadIndex = layer.load(2);
                    $.ajax({
                        url: baseUrl + "/mobile/cache/agv/call",
                        headers: {'token': localStorage.getItem('token')},
                        data: JSON.stringify({
                            orgSite: formData.field.orgSite,
                            tarSite: formData.field.tarSite,
                            barcode: formData.field.barcode
                        }),
                        contentType: 'application/json;charset=UTF-8',
                        method: 'POST',
                        success: function(res) {
                            layer.close(loadIndex);
                            if (res.code === 200) {
                                layer.close(index);
                                layer.msg('呼叫AGV成功', {icon: 1});
                                tableReload();
                            } else if (res.code === 403) {
                                top.location.href = baseUrl + "/";
                            } else {
                                layer.msg(res.msg || '呼叫AGV失败', {icon: 2});
                            }
                        },
                        error: function() {
                            layer.close(loadIndex);
                            layer.msg('网络请求失败', {icon: 2});
                        }
                    });
                    return false;
                });
            }
        });
    }
});
// 关闭动作
src/main/webapp/views/task/task.html
@@ -65,6 +65,9 @@
    {{#if (d.ioType === 107) { }}
    <a class="layui-btn layui-btn-warm layui-btn-xs btn-pick" lay-event="pick">盘</a>
    {{# } }}
    {{#if (d.taskType === 'agv') { }}
    <a class="layui-btn layui-btn-normal layui-btn-xs btn-callAgv" lay-event="callAgv">呼叫AGV</a>
    {{# } }}
</script>
<script type="text/javascript" src="../../static/js/jquery/jquery-3.3.1.min.js"></script>