package com.zy.asrs.task.handler; import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSONObject; import com.baomidou.mybatisplus.mapper.EntityWrapper; import com.zy.asrs.entity.Task; import com.zy.asrs.entity.TaskLog; import com.zy.asrs.entity.WrkMast; import com.zy.asrs.mapper.BasStationMapper; import com.zy.asrs.mapper.WrkMastMapper; import com.zy.asrs.service.ApiLogService; import com.zy.asrs.service.TaskLogService; import com.zy.asrs.service.TaskService; import com.zy.common.constant.ApiInterfaceConstant; import com.zy.common.utils.HttpHandler; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.BeanUtils; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import javax.annotation.Resource; import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.stream.Collectors; /** * @author pang.jiabao * @description AGV交互相关定时任务处理类 * @createDate 2025/11/18 14:42 */ @Slf4j @Service public class AgvHandler { @Resource private WrkMastMapper wrkMastMapper; @Resource private ApiLogService apiLogService; @Resource private TaskService taskService; @Resource private TaskLogService taskLogService; @Resource private BasStationMapper basStationMapper; @Value("${Agv.sendTask}") private boolean agvSendTask; /** * 呼叫agv搬运 */ public void callAgv(List taskList) { if (!agvSendTask) { return; } for (Task task : taskList) { // 呼叫agv String response = ""; boolean success = false; String url = ApiInterfaceConstant.AGV_IP + ApiInterfaceConstant.AGV_CREATE_TASK_PATH; String namespace = ""; switch (task.getIoType()) { case 1: case 10: case 53: case 57: namespace = "入库"; break; case 3: namespace = "转移"; break; case 101: case 110: case 103: case 107: namespace = "出库"; break; default: } String body = getRequest(task,namespace); try { // 使用仙工M4接口 response = new HttpHandler.Builder() .setUri(ApiInterfaceConstant.AGV_IP) .setPath(ApiInterfaceConstant.AGV_CREATE_TASK_PATH) .setJson(body) .build() .doPost(); JSONObject jsonObject = JSON.parseObject(response); if (jsonObject.getInteger("code").equals(200)) { success = true; task.setWrkSts(8L); taskService.updateById(task); log.info(namespace + "呼叫agv搬运成功:{}", task.getId()); } else { log.error(namespace + "呼叫agv搬运失败!!!url:{};request:{};response:{}", url, body, response); } } catch (Exception e) { log.error(namespace + "呼叫agv搬运异常", e); } finally { try { // 保存接口日志 apiLogService.save( namespace + "呼叫agv搬运", url, null, "127.0.0.1", body, response, success ); } catch (Exception e) { log.error(namespace + "呼叫agv保存接口日志异常:", e); } } } } /** * 构造请求内容(仙工M4格式) */ private String getRequest(Task task, String nameSpace) { JSONObject object = new JSONObject(); // taskId使用任务ID,格式:T + 任务ID object.put("taskId", "T" + task.getId()); object.put("fromBin", task.getSourceStaNo()); object.put("toBin", task.getStaNo()); // robotGroup从invWh字段获取,如果没有则使用默认值 String robotGroup = task.getInvWh(); if (robotGroup == null || robotGroup.isEmpty()) { robotGroup = "Group-001"; // 默认机器人组 } object.put("robotGroup", robotGroup); // kind根据任务类型映射 String kind = ""; switch (nameSpace) { case "入库": kind = "实托入库"; break; case "出库": kind = "实托出库"; break; case "转移": kind = "货物转运"; break; default: kind = "货物转运"; } object.put("kind", kind); return object.toJSONString(); } /** * 任务完成转历史 释放暂存点 */ @Transactional(rollbackFor = Exception.class) public void moveTaskToHistory(List taskList) { // 写入历史表 for (Task task : taskList) { TaskLog log = new TaskLog(); BeanUtils.copyProperties(task, log); taskLogService.insert(log); } // 批量删除原任务 List taskIds = taskList.stream().map(Task::getId).collect(Collectors.toList()); taskService.delete(new EntityWrapper().in("id",taskIds)); // 批量更新暂存点状态 List locOList = new ArrayList<>(); List locFList = new ArrayList<>(); for (Task task : taskList) { String sourceStaNo = task.getSourceStaNo(); String staNo = task.getStaNo(); if (task.getIoType() == 3) { locOList.add(sourceStaNo); locFList.add(staNo); } else if (task.getIoType() < 100) { locOList.add(sourceStaNo); } else { locFList.add(staNo); } } if (!locOList.isEmpty()) { basStationMapper.updateLocStsBatch(locOList, "O"); } if (!locFList.isEmpty()) { basStationMapper.updateLocStsBatch(locFList, "F"); } log.info("agv任务档转历史成功:{}", taskIds); } /** * 货物到达出库口,生成agv任务 */ public void createAgvOutTasks(List sites) { // 获取到可用出库站点的任务 List wrkMastList = wrkMastMapper.selectList(new EntityWrapper().eq("call_agv", 1).in("sta_no",sites)); for(WrkMast wrkMast:wrkMastList) { // todo 计算agv目标暂存位 int endSite = 2004; // 插入agv任务 Task task = new Task(wrkMast.getWrkNo(), 7L, wrkMast.getIoType(), String.valueOf(wrkMast.getStaNo()), String.valueOf(endSite), null, wrkMast.getBarcode()); taskService.insert(task); // 更新任务档agv搬运标识 wrkMast.setCallAgv(2); wrkMastMapper.updateById(wrkMast); // 更新暂存位状态 S.入库预约 basStationMapper.updateLocStsBatch( Collections.singletonList(String.valueOf(endSite)), "S"); } } /** * 取消AGV任务(仙工M4接口) * @param task 任务对象 * @return 是否成功 */ public boolean cancelAgvTask(Task task) { if (!agvSendTask) { return false; } if (task == null || task.getId() == null) { log.error("取消AGV任务失败:任务或任务ID为空"); return false; } String response = ""; boolean success = false; String url = ApiInterfaceConstant.AGV_IP + ApiInterfaceConstant.AGV_CANCEL_TASK_PATH; String namespace = ""; String kind = ""; // 根据任务类型确定kind和namespace switch (task.getIoType()) { case 1: case 10: case 53: case 57: namespace = "入库"; kind = "实托入库"; break; case 3: namespace = "转移"; kind = "货物转运"; break; case 101: case 110: case 103: case 107: namespace = "出库"; kind = "实托出库"; break; default: kind = "货物转运"; } // 构造取消任务请求 JSONObject cancelRequest = new JSONObject(); cancelRequest.put("taskId", "T" + task.getId()); cancelRequest.put("kind", kind); String body = cancelRequest.toJSONString(); try { response = new HttpHandler.Builder() .setUri(ApiInterfaceConstant.AGV_IP) .setPath(ApiInterfaceConstant.AGV_CANCEL_TASK_PATH) .setJson(body) .build() .doPost(); JSONObject jsonObject = JSON.parseObject(response); if (jsonObject.getInteger("code") != null && jsonObject.getInteger("code").equals(200)) { success = true; log.info(namespace + "取消AGV任务成功:{}", task.getId()); } else { log.error(namespace + "取消AGV任务失败!!!url:{};request:{};response:{}", url, body, response); } } catch (Exception e) { log.error(namespace + "取消AGV任务异常", e); } finally { try { // 保存接口日志 apiLogService.save( namespace + "取消AGV任务", url, null, "127.0.0.1", body, response, success ); } catch (Exception e) { log.error(namespace + "取消AGV任务保存接口日志异常:", e); } } return success; } }