| src/main/java/com/zy/asrs/controller/LocDetlController.java | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| src/main/java/com/zy/asrs/controller/OpenController.java | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| src/main/java/com/zy/asrs/controller/StaDescController.java | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| src/main/java/com/zy/asrs/controller/WrkMastController.java | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| src/main/java/com/zy/asrs/entity/AgvCallbackDto.java | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| src/main/java/com/zy/asrs/entity/LocDetl.java | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| src/main/java/com/zy/asrs/entity/WrkMast.java | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| src/main/java/com/zy/asrs/service/impl/OpenServiceImpl.java | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| src/main/java/com/zy/asrs/task/handler/AgvHandler.java | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| src/main/java/com/zy/common/constant/ApiInterfaceConstant.java | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 |
src/main/java/com/zy/asrs/controller/LocDetlController.java
@@ -129,7 +129,14 @@ @RequestMapping(value = "/locDetl/{id}/auth") @ManagerAuth public R get(@PathVariable("id") String id) { return R.ok(locDetlService.selectById(String.valueOf(id))); // asr_loc_detl 表没有 id 主键,使用 loc_no 查询 // 注意:一个 loc_no 可能对应多条记录,返回第一条 List<LocDetl> list = locDetlService.selectList(new EntityWrapper<LocDetl>().eq("loc_no", id).last("limit 1")); if (!list.isEmpty()) { return R.ok(list.get(0)); } // 返回 null 而不是错误,避免前端解析失败 return R.ok(null); } @RequestMapping(value = "/locDetl/auth") @@ -234,13 +241,29 @@ @RequestMapping(value = "/locDetl/update/auth") @ManagerAuth(memo = "库位明细修改") public R update(LocDetl locDetl) { if (Cools.isEmpty(locDetl) || null == locDetl.getMatnr()) { return R.error(); if (Cools.isEmpty(locDetl) || null == locDetl.getMatnr() || Cools.isEmpty(locDetl.getLocNo())) { return R.error("参数不完整,需要 locNo 和 matnr"); } locDetl.setModiUser(getUserId()); locDetl.setModiTime(new Date()); locDetlService.updateById(locDetl); return R.ok(); // asr_loc_detl 表没有 id 主键,使用 EntityWrapper 根据 loc_no 和 matnr 更新 EntityWrapper<LocDetl> wrapper = new EntityWrapper<>(); wrapper.eq("loc_no", locDetl.getLocNo()); wrapper.eq("matnr", locDetl.getMatnr()); // 如果有批次信息,也加入条件 if (!Cools.isEmpty(locDetl.getBatch())) { wrapper.eq("batch", locDetl.getBatch()); } else { wrapper.andNew("(batch IS NULL OR batch = '')"); } boolean result = locDetlService.update(locDetl, wrapper); if (result) { return R.ok(); } return R.error("更新失败,未找到匹配的记录"); } @RequestMapping(value = "/locDetl/delete/auth") src/main/java/com/zy/asrs/controller/OpenController.java
@@ -54,7 +54,9 @@ public synchronized R agvCallback(@RequestHeader(required = false) String appkey, @RequestBody(required = false) AgvCallbackDto param, HttpServletRequest request) { auth(appkey, param, request); return openService.agvCallback(param); } src/main/java/com/zy/asrs/controller/StaDescController.java
@@ -12,12 +12,8 @@ import com.core.common.R; import com.zy.asrs.entity.StaDesc; import com.zy.asrs.entity.param.StaDescInitParam; import com.zy.asrs.mapper.StaDescMapper; import com.zy.asrs.service.StaDescService; import com.zy.common.web.BaseController; import org.apache.ibatis.session.ExecutorType; import org.apache.ibatis.session.SqlSession; import org.apache.ibatis.session.SqlSessionFactory; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; @@ -31,24 +27,33 @@ private static final Logger log = LoggerFactory.getLogger(StaDescController.class); @Autowired private StaDescService staDescService; @Autowired private SqlSessionFactory sqlSessionFactory; @RequestMapping(value = "/staDesc/init/auth") @ManagerAuth(memo = "初始化站点路径") public R init(StaDescInitParam param) { try { // 参数校验:确保堆垛机号不为空 if (Cools.isEmpty(param.getCrnNo())) { return R.error("堆垛机号不能为空"); } // 格式化开关:只删除当前堆垛机号的数据,而不是全部数据 if (param.getTypeDesc() == 1) { staDescService.delete(new EntityWrapper<>()); staDescService.delete(new EntityWrapper<StaDesc>() .eq("crn_no", param.getCrnNo()) ); } String[] startStaList = param.getStartStaList().split(";"); String[] endStaList = param.getEndStaList().split(";"); List<StaDesc> staDescList = new ArrayList<>(); SqlSession sqlSession = sqlSessionFactory.openSession(ExecutorType.BATCH, false); StaDescMapper sqlSessionMapper = sqlSession.getMapper(StaDescMapper.class); Date currentTime = new Date(); Long userId = getUserId(); int insertCount = 0; // SQL Server 批量插入时无法获取自增主键,改为循环单个插入 for (String startSta : startStaList) { for (String endSta : endStaList) { for (Integer type : param.getType()) { // 检查是否已存在 int sameRes = staDescService.selectCount(new EntityWrapper<StaDesc>() .eq("type_no", type) .eq("stn_no", Integer.parseInt(startSta)) @@ -57,28 +62,27 @@ if (sameRes > 0) { continue; } // 创建并插入单条记录 StaDesc staDesc = new StaDesc(); staDesc.setCrnNo(param.getCrnNo()); staDesc.setTypeNo(type); staDesc.setStnNo(Integer.parseInt(startSta)); staDesc.setCrnStn(Integer.parseInt(endSta)); staDesc.setModiUser(getUserId()); staDesc.setModiTime(new Date()); staDesc.setAppeUser(getUserId()); staDesc.setAppeTime(new Date()); // staDescList.add(staDesc); sqlSessionMapper.insert(staDesc); staDesc.setModiUser(userId); staDesc.setModiTime(currentTime); staDesc.setAppeUser(userId); staDesc.setAppeTime(currentTime); // 单个插入,确保能正确获取自增主键 if (staDescService.insert(staDesc)) { insertCount++; } } } } try { sqlSession.commit(); sqlSession.close(); } catch (Exception e) { log.error("初始化站点路径异常===>sql异常:{}", e.getMessage()); } // staDescService.insertBatch(staDescList); log.info("初始化站点路径完成,共插入 {} 条记录", insertCount); } catch (Exception e) { log.error("初始化站点路径异常:{}", e.getMessage()); return R.error("初始化站点路径异常:" + e.getMessage()); src/main/java/com/zy/asrs/controller/WrkMastController.java
@@ -56,6 +56,10 @@ private <T> void convert(Map<String, Object> map, EntityWrapper<T> wrapper) { for (Map.Entry<String, Object> entry : map.entrySet()) { String val = String.valueOf(entry.getValue()); // 跳过空值和 "null" 字符串 if (Cools.isEmpty(val) || "null".equals(val)) { continue; } if (val.contains(RANGE_TIME_LINK)) { String[] dates = val.split(RANGE_TIME_LINK); wrapper.ge(entry.getKey(), DateUtils.convert(dates[0])); src/main/java/com/zy/asrs/entity/AgvCallbackDto.java
@@ -10,9 +10,14 @@ @Data public class AgvCallbackDto { /** * 运单编号 * 运单编号(兼容旧接口) */ private String id; /** * 任务id(新接口使用) */ private String taskId; /** * 运单类型 @@ -39,11 +44,16 @@ private String toBin; /** * 分配AGV * 分配AGV(兼容旧接口) */ private String robotName; /** * 机器人组(新接口使用) */ private String robotGroup; /** * 在库口 */ private Boolean atPort; src/main/java/com/zy/asrs/entity/LocDetl.java
@@ -3,9 +3,7 @@ import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; import com.alibaba.excel.annotation.ExcelProperty; import com.baomidou.mybatisplus.annotations.TableField; import com.baomidou.mybatisplus.annotations.TableId; import com.baomidou.mybatisplus.annotations.TableName; import com.baomidou.mybatisplus.enums.IdType; import com.baomidou.mybatisplus.mapper.EntityWrapper; import com.core.common.Cools; import com.core.common.SpringUtils; @@ -32,9 +30,10 @@ private static final long serialVersionUID = 1L; @TableId(value = "id", type = IdType.AUTO) private Long id; // 注意:asr_loc_detl 表中没有 id 列,因此不使用 @TableId 注解 // 如果后续需要添加主键,请先确认数据库表结构 // @TableId(value = "id", type = IdType.AUTO) // private Long id; @TableField("loc_id") private Long locId; src/main/java/com/zy/asrs/entity/WrkMast.java
@@ -345,13 +345,16 @@ } public String getCallAgv$() { if (this.callAgv == null) { return ""; } switch (this.callAgv) { case 0: return "未呼叫"; case 1: return "准备呼叫"; case 2: return "已呼叫"; default: return ""; } return ""; } public String getWrkSts$() { src/main/java/com/zy/asrs/service/impl/OpenServiceImpl.java
@@ -59,21 +59,92 @@ private TaskService taskService; @Override @Transactional(rollbackFor = Exception.class) public R agvCallback(AgvCallbackDto param) { String id = param.getId(); Task task = taskService.selectById(id); log.debug("agvCallback param:{}", param); // 优先使用taskId,如果没有则使用id(向后兼容) String taskId = Cools.isEmpty(param.getTaskId()) ? param.getId() : param.getTaskId(); if (Cools.isEmpty(taskId)) { 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(), param.getKind()); // 根据taskId查询任务 Task task = null; try { // 尝试将taskId解析为Long类型的id Long taskIdLong = Long.parseLong(taskId); task = taskService.selectById(taskIdLong); } catch (NumberFormatException e) { // 如果不是数字,尝试通过其他字段查询(如sheetNo等) log.debug("taskId不是数字格式,尝试通过其他字段查询,taskId:{}", taskId); task = taskService.selectOne( new EntityWrapper<Task>().eq("sheet_no", taskId) ); } if (task == null) { return R.parse(id +":id不存在"); log.warn("未找到对应的任务,taskId:{}", taskId); return R.error("任务不存在,taskId:" + taskId); } switch (param.getStatus()) { case "Assigned":task.setInvWh(param.getRobotName());break; case "Done":task.setWrkSts(9L);break; case "Failed": case "Cancelled": default: // 更新任务信息 if (!Cools.isEmpty(param.getFromBin())) { task.setSourceStaNo(param.getFromBin()); } taskService.updateById(task); if (!Cools.isEmpty(param.getToBin())) { task.setLocNo(param.getToBin()); } // 优先使用robotGroup,如果没有则使用robotName(向后兼容) String robotGroup = Cools.isEmpty(param.getRobotGroup()) ? param.getRobotName() : param.getRobotGroup(); if (!Cools.isEmpty(robotGroup)) { task.setInvWh(robotGroup); } task.setModiTime(new Date()); // 如果有status字段,按原有逻辑处理(向后兼容) if (!Cools.isEmpty(param.getStatus())) { switch (param.getStatus()) { case "Assigned": if (Cools.isEmpty(robotGroup)) { task.setInvWh(param.getRobotName()); } break; case "Done": task.setWrkSts(9L); break; case "Failed": case "Cancelled": default: break; } } // 根据任务类型进行相应处理 if (!Cools.isEmpty(param.getKind())) { String kind = param.getKind(); if ("货物转运".equals(kind)) { log.info("处理货物转运任务,taskId:{}", taskId); } else if ("实托入库".equals(kind)) { log.info("处理实托入库任务,taskId:{}", taskId); } else if ("实托出库".equals(kind)) { log.info("处理实托出库任务,taskId:{}", taskId); } } // 保存任务更新 if (!taskService.updateById(task)) { log.error("更新任务失败,taskId:{}", taskId); return R.error("更新任务失败"); } log.info("AGV任务回调处理成功,taskId:{}", taskId); return R.ok(); } src/main/java/com/zy/asrs/task/handler/AgvHandler.java
@@ -3,7 +3,6 @@ import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSONObject; import com.baomidou.mybatisplus.mapper.EntityWrapper; import com.core.common.R; import com.zy.asrs.entity.Task; import com.zy.asrs.entity.TaskLog; import com.zy.asrs.entity.WrkMast; @@ -22,11 +21,8 @@ import javax.annotation.Resource; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.List; import java.util.function.Function; import java.util.function.Predicate; import java.util.stream.Collectors; /** @@ -69,7 +65,7 @@ // 呼叫agv String response = ""; boolean success = false; String url = ApiInterfaceConstant.AGV_IP + ApiInterfaceConstant.AGV_CALL_CARRY_PATH; String url = ApiInterfaceConstant.AGV_IP + ApiInterfaceConstant.AGV_CREATE_TASK_PATH; String namespace = ""; switch (task.getIoType()) { case 1: @@ -91,9 +87,10 @@ } String body = getRequest(task,namespace); try { // 使用仙工M4接口 response = new HttpHandler.Builder() .setUri(ApiInterfaceConstant.AGV_IP) .setPath(ApiInterfaceConstant.AGV_CALL_CARRY_PATH) .setPath(ApiInterfaceConstant.AGV_CREATE_TASK_PATH) .setJson(body) .build() .doPost(); @@ -128,34 +125,36 @@ } /** * 构造请求内容 * 构造请求内容(仙工M4格式) */ private String getRequest(Task task, String nameSpace) { JSONObject object = new JSONObject(); object.put("entityName", "ContainerTransportOrder"); JSONObject entityValue = new JSONObject(); entityValue.put("id", task.getId()); // 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 = "inBound"; kind = "实托入库"; break; case "出库": kind = "outBound"; kind = "实托出库"; break; case "转移": kind = "moveBound"; kind = "货物转运"; break; default: kind = "货物转运"; } entityValue.put("kind", kind); entityValue.put("status", "Created"); entityValue.put("priority", 0); entityValue.put("container", task.getBarcode()); entityValue.put("fromBin", task.getSourceStaNo()); entityValue.put("toBin", task.getStaNo()); entityValue.put("emptyFlag", task.getIoType() == 10 ? 1 : 2); // 空托1,满托2 agv带着告诉输送线plc object.put("entityValue", entityValue.toJSONString()); object.put("kind", kind); return object.toJSONString(); } @@ -225,4 +224,92 @@ 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; } } src/main/java/com/zy/common/constant/ApiInterfaceConstant.java
@@ -36,8 +36,13 @@ public static final String AGV_IP = "http://127.0.0.1:8080/yhfzwms/open/asrs"; /** * 呼叫AGV搬运 * 仙工M4 - 创建任务(货物转运、实托入库,实托出库) */ public static final String AGV_CALL_CARRY_PATH = "/api/entity/create/one"; public static final String AGV_CREATE_TASK_PATH = "/api/agv/inbond"; /** * 仙工M4 - 取消任务 */ public static final String AGV_CANCEL_TASK_PATH = "/api/agv/cancelTransport"; }