agv增加一个新单号防重复 ,增加一个手动呼叫agv
| | |
| | | @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() { |
| | | } |
| | | |
| | |
| | | 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; |
| | |
| | | |
| | | // 获取工作号 |
| | | 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.入库 |
| | |
| | | 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.库格移载 |
| | |
| | | } |
| | | // 获取工作号 |
| | | 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") |
| | |
| | | .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("保存工作档失败"); |
| | | } |
| | |
| | | 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); |
| | |
| | | */ |
| | | 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 |
| | |
| | | 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; |
| | |
| | | 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(); |
| | |
| | | // 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); |
| | |
| | | |
| | | // 构造取消任务请求 |
| | | 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(); |
| | | |
| | |
| | | */ |
| | | 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"; |
| | | |
| New file |
| | |
| | | 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()); |
| | | } |
| | | } |
| | |
| | | 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; |
| | |
| | | |
| | | // 获取工作号 |
| | | 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.入库 |
| | |
| | | , {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', |
| | |
| | | }, function () { |
| | | }); |
| | | break; |
| | | // 呼叫AGV |
| | | case 'callAgv': |
| | | callAgvMove(data); |
| | | break; |
| | | } |
| | | }); |
| | | |
| | |
| | | |
| | | 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; |
| | | }); |
| | | } |
| | | }); |
| | | } |
| | | |
| | | }); |
| | | |
| | | // 关闭动作 |
| | |
| | | {{#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> |