diff --git a/youchain-common/src/main/java/com/youchain/exception/handler/LesResult.java b/youchain-common/src/main/java/com/youchain/exception/handler/LesResult.java index ccf77c2..e13d809 100644 --- a/youchain-common/src/main/java/com/youchain/exception/handler/LesResult.java +++ b/youchain-common/src/main/java/com/youchain/exception/handler/LesResult.java @@ -1,35 +1,27 @@ package com.youchain.exception.handler; -import lombok.Data; +import com.alibaba.fastjson.JSONObject; +import lombok.extern.slf4j.Slf4j; -import java.time.LocalDateTime; - -@Data +@Slf4j public class LesResult { - private Object data;//数据 - private String debugMsg;//调试信息 - private String displayMsg;//描述信息,失败原因 - private String requestId;//请求id - private int resultCode;//返回码 - private String serverTime;//请求时间,服务器时间戳 - - public static LesResult fail(String requestId, String displayMsg) { - return result(requestId,400, displayMsg, null); + public static JSONObject fail(String requestId, String displayMsg) { + return result(requestId, 400, displayMsg, null); } - public static LesResult success(String requestId) { + public static JSONObject success(String requestId) { return result(requestId, 2000, "", null); } - public static LesResult result(String requestId, int resultCode, String displayMsg, Object data) { - LesResult lesResult = new LesResult(); - lesResult.setRequestId(requestId); - lesResult.setServerTime(LocalDateTime.now().toString()); - lesResult.setResultCode(resultCode); - lesResult.setDisplayMsg(displayMsg); - lesResult.setDebugMsg(""); - lesResult.setData(data); - return lesResult; + public static JSONObject result(String requestId, int resultCode, String displayMsg, Object data) { + JSONObject jsonObject = new JSONObject(true); // true 保持顺序 + jsonObject.put("requestId", requestId); + jsonObject.put("serverTime", System.currentTimeMillis()); // 数值类型时间戳 + jsonObject.put("resultCode", resultCode); + jsonObject.put("displayMsg", displayMsg == null ? "" : displayMsg); + jsonObject.put("debugMsg", ""); + jsonObject.put("data", data == null ? "" : data); + return jsonObject; } } diff --git a/youchain-system/src/main/java/com/youchain/businessdata/inputJson/LesRequest.java b/youchain-system/src/main/java/com/youchain/businessdata/inputJson/LesRequest.java index 73b0f11..d7a3ff7 100644 --- a/youchain-system/src/main/java/com/youchain/businessdata/inputJson/LesRequest.java +++ b/youchain-system/src/main/java/com/youchain/businessdata/inputJson/LesRequest.java @@ -1,5 +1,6 @@ package com.youchain.businessdata.inputJson; +import com.fasterxml.jackson.annotation.JsonPropertyOrder; import io.swagger.annotations.ApiModelProperty; import lombok.Data; @@ -33,6 +34,6 @@ public class LesRequest { String onlineNo; @ApiModelProperty(value = "节点", required = true) - List positionCodes; + List positionCodePath; } diff --git a/youchain-system/src/main/java/com/youchain/businessdata/repository/AgvTaskRepository.java b/youchain-system/src/main/java/com/youchain/businessdata/repository/AgvTaskRepository.java index ddcd4df..1c310e9 100644 --- a/youchain-system/src/main/java/com/youchain/businessdata/repository/AgvTaskRepository.java +++ b/youchain-system/src/main/java/com/youchain/businessdata/repository/AgvTaskRepository.java @@ -30,59 +30,12 @@ import java.util.Map; **/ public interface AgvTaskRepository extends JpaRepository, JpaSpecificationExecutor { - /** - * 本周任务数统计 - * @return - */ - @Query(value = " SELECT " + - " weekDay," + - " taskCount" + - " FROM (" + - " SELECT " + - " 0 AS sort_order," + - " NULL AS date," + - " '总计' AS weekDay," + - " SUM(task_count) AS taskCount" + - " FROM (" + - " SELECT " + - " DATE(create_time) AS date," + - " COUNT(id) AS task_count" + - " FROM data_agv_task " + - " WHERE " + - " WEEK(create_time, 1) = WEEK(CURDATE(), 1)" + - " GROUP BY DATE(create_time)" + - " ) sub" + - " UNION ALL" + - " SELECT " + - " 1 AS sort_order," + - " dr.date," + - " CASE " + - " WHEN WEEKDAY(dr.date) = 0 THEN '周一'" + - " WHEN WEEKDAY(dr.date) = 1 THEN '周二'" + - " WHEN WEEKDAY(dr.date) = 2 THEN '周三'" + - " WHEN WEEKDAY(dr.date) = 3 THEN '周四'" + - " WHEN WEEKDAY(dr.date) = 4 THEN '周五'" + - " WHEN WEEKDAY(dr.date) = 5 THEN '周六'" + - " WHEN WEEKDAY(dr.date) = 6 THEN '周日'" + - " END AS weekDay," + - " COALESCE(dt.task_count, 0) AS taskCount" + - " FROM " + - " (SELECT " + - " CURDATE() - INTERVAL (WEEKDAY(CURDATE())) DAY + INTERVAL weeks DAY AS date" + - " FROM " + - " (SELECT 0 AS weeks UNION ALL SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3 UNION ALL SELECT 4 UNION ALL SELECT 5 UNION ALL SELECT 6) weeks" + - " ) dr" + - " LEFT JOIN (" + - " SELECT " + - " DATE(create_time) AS date," + - " COUNT(id) AS task_count" + - " FROM data_agv_task " + - " WHERE " + - " WEEK(create_time, 1) = WEEK(CURDATE(), 1)" + - " GROUP BY DATE(create_time)" + - " ) dt " + - " ON dr.date = dt.date" + - " ) result" + - " ORDER BY sort_order, date;", nativeQuery = true) - List queryWeeklyTaskCounts(); + @Query(value = "select count(agv.id) from AgvTask agv where agv.stockCode=:stockCode and agv.startSlotCode=:srcPointCode and agv.endSlotCode=:endPointCode and agv.status in ('OPEN','ATCALL','UP_CONTAINER') ") + int isAGVTaskDuplicate(String stockCode, String srcPointCode, String endPointCode); + + @Query(value = "select count(agv.id) from AgvTask agv where agv.startSlotCode=:startSlotCode and agv.type=:type and agv.jobType=:jobType and agv.status in ('OPEN','ATCALL','UP_CONTAINER') ") + int findByStartSlotCode(String startSlotCode, String type, String jobType); + + @Query(value = "select count(agv.id) from AgvTask agv where agv.endSlotCode=:endSlotCode and agv.type=:type and agv.jobType=:jobType and agv.status in ('OPEN','ATCALL','UP_CONTAINER') ") + int findByEndSlotCode(String endSlotCode, String type, String jobType); } diff --git a/youchain-system/src/main/java/com/youchain/businessdata/repository/LesRepository.java b/youchain-system/src/main/java/com/youchain/businessdata/repository/LesRepository.java index aed9cfb..8052086 100644 --- a/youchain-system/src/main/java/com/youchain/businessdata/repository/LesRepository.java +++ b/youchain-system/src/main/java/com/youchain/businessdata/repository/LesRepository.java @@ -1,6 +1,5 @@ package com.youchain.businessdata.repository; -import com.youchain.businessdata.domain.AgvTask; import com.youchain.businessdata.domain.Les; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.JpaSpecificationExecutor; diff --git a/youchain-system/src/main/java/com/youchain/businessdata/rest/LesController.java b/youchain-system/src/main/java/com/youchain/businessdata/rest/LesController.java index 4c5e9a1..9ec78aa 100644 --- a/youchain-system/src/main/java/com/youchain/businessdata/rest/LesController.java +++ b/youchain-system/src/main/java/com/youchain/businessdata/rest/LesController.java @@ -76,6 +76,7 @@ public class LesController { public ResponseEntity genAgvSchedulingTask(@RequestBody LesRequest lesRequest) { String id = lesRequest.getGuId();//请求id try { + lesService.genAgvSchedulingTask(lesRequest); return new ResponseEntity<>(LesResult.success(id), HttpStatus.OK); } catch (Exception e) { return new ResponseEntity<>(LesResult.fail(id, e.getMessage()), HttpStatus.BAD_REQUEST); diff --git a/youchain-system/src/main/java/com/youchain/businessdata/service/AgvTaskService.java b/youchain-system/src/main/java/com/youchain/businessdata/service/AgvTaskService.java index 4fa5bb3..372a1bf 100644 --- a/youchain-system/src/main/java/com/youchain/businessdata/service/AgvTaskService.java +++ b/youchain-system/src/main/java/com/youchain/businessdata/service/AgvTaskService.java @@ -101,5 +101,29 @@ public interface AgvTaskService { */ AgvTask createAgvTask(String bizStatus, Stock stock, Point srcPoint, Point endPoint,String jobType); + /** + * 根据容器查询任务 + * + * @param stockCode 容器 + */ + Boolean isAGVTaskDuplicate(String stockCode, String srcPointCode, String endPointCode); + + /** + * 根据起点查询是否有重复任务 + * + * @param startSlotCode 点位 + * @param type 任务类型 + * @param jobType 作业类型 + */ + Boolean findByStartSlotCode(String startSlotCode, String type, String jobType); + + /** + * 根据终点查询是否有重复任务 + * + * @param endSlotCode 点位 + * @param type 任务类型 + * @param jobType 作业类型 + */ + Boolean findByEndSlotCode(String endSlotCode, String type, String jobType); } diff --git a/youchain-system/src/main/java/com/youchain/businessdata/service/KMReService.java b/youchain-system/src/main/java/com/youchain/businessdata/service/KMReService.java new file mode 100644 index 0000000..95f8dfd --- /dev/null +++ b/youchain-system/src/main/java/com/youchain/businessdata/service/KMReService.java @@ -0,0 +1,100 @@ +package com.youchain.businessdata.service; + +import com.youchain.businessdata.domain.AgvTask; + +import java.util.List; + +public interface KMReService { + /** + * 容器入场JSON + * + * @param containerCode 容器编号 + * @param position 点位 + */ + String containerInJson(String containerCode, String position); + + /** + * 容器入场 + * + * @param containerCode 容器 + * @param position 点位 + * @param itemCode 物料 + */ + void containerIn(String containerCode, String position, String itemCode); + + /** + * 容器出场JSON + * + * @param containerCode 容器编号 + */ + String containerOutJson(String containerCode); + + /** + * 容器出场 + * + * @param containerCode 容器 + */ + void containerOut(String containerCode); + + /** + * 下发容器入场或出场或放行 + * + * @param url 接口地址 + * @param json 接口json + */ + void sendAgvTaskToContainer(String url, String json); + + /** + * 下发agv叉车任务JSON + * + * @param agvTask 任务 + */ + String sendAgvTaskCcJson(AgvTask agvTask); + + + /** + * 下发agv货架任务JSON + * + * @param agvTask 任务 + */ + String sendAgvTaskHjJson(AgvTask agvTask); + + /** + * 下发agv滚筒任务JSON + * + * @param agvTask 任务 + */ + String sendAgvTaskGtJson(AgvTask agvTask); + + /** + * 下发agv牵引车任务JSON + * + * @param agvTask 任务 + * @param tugModels 牵引车型号 + */ + String sendAgvTaskQYCJson(AgvTask agvTask, List tugModels); + + /** + * 下发agv任务 + * + * @param agvTasks 任务 + */ + void sendAgvTask(AgvTask agvTasks, String json); + + /** + * 任务回报更新状态 + * + * @param agvTask 任务 + * @param status 状态 + * @param containerCode 容器 + * @param currentPosition 当前位置 + */ + void missionStateCallback(AgvTask agvTask, String status, String containerCode, String currentPosition); + + /** + * 任务放行Json + * + * @param agvTask 任务 + */ + String operationFeedbackJson(AgvTask agvTask); +} diff --git a/youchain-system/src/main/java/com/youchain/businessdata/service/LesService.java b/youchain-system/src/main/java/com/youchain/businessdata/service/LesService.java index 8211587..710e0cc 100644 --- a/youchain-system/src/main/java/com/youchain/businessdata/service/LesService.java +++ b/youchain-system/src/main/java/com/youchain/businessdata/service/LesService.java @@ -75,4 +75,12 @@ public interface LesService { */ void genAgvSchedulingTask( LesRequest lesRequest); + /** + * LES任务回调 + * @param currentPositionCode 当前点位 + * @param taskCode 任务号 + * @return json + */ + String lesCallBack(String currentPositionCode,String taskCode); + } diff --git a/youchain-system/src/main/java/com/youchain/businessdata/service/dto/LesDto.java b/youchain-system/src/main/java/com/youchain/businessdata/service/dto/LesDto.java index 7099574..498659b 100644 --- a/youchain-system/src/main/java/com/youchain/businessdata/service/dto/LesDto.java +++ b/youchain-system/src/main/java/com/youchain/businessdata/service/dto/LesDto.java @@ -1,9 +1,7 @@ package com.youchain.businessdata.service.dto; -import io.swagger.annotations.ApiModelProperty; import lombok.Data; -import javax.persistence.Column; import java.sql.Timestamp; diff --git a/youchain-system/src/main/java/com/youchain/businessdata/service/impl/AgvTaskServiceImpl.java b/youchain-system/src/main/java/com/youchain/businessdata/service/impl/AgvTaskServiceImpl.java index 24ea481..3959a6c 100644 --- a/youchain-system/src/main/java/com/youchain/businessdata/service/impl/AgvTaskServiceImpl.java +++ b/youchain-system/src/main/java/com/youchain/businessdata/service/impl/AgvTaskServiceImpl.java @@ -34,6 +34,7 @@ import org.springframework.data.domain.Pageable; import java.util.*; import java.io.IOException; import java.util.stream.Collectors; +import javax.persistence.Query; import javax.servlet.http.HttpServletResponse; @@ -138,4 +139,19 @@ public class AgvTaskServiceImpl implements AgvTaskService { return agvTask; } + @Override + public Boolean isAGVTaskDuplicate(String stockCode, String srcPointCode, String endPointCode) { + return agvTaskRepository.isAGVTaskDuplicate(stockCode, srcPointCode, endPointCode)>0; + } + + @Override + public Boolean findByStartSlotCode(String startSlotCode, String type, String jobType) { + return agvTaskRepository.findByStartSlotCode(startSlotCode, type, jobType)>0; + } + + @Override + public Boolean findByEndSlotCode(String endSlotCode, String type, String jobType) { + return agvTaskRepository.findByEndSlotCode(endSlotCode, type, jobType)>0; + } + } diff --git a/youchain-system/src/main/java/com/youchain/businessdata/service/impl/KMReServiceImpl.java b/youchain-system/src/main/java/com/youchain/businessdata/service/impl/KMReServiceImpl.java new file mode 100644 index 0000000..3df0f56 --- /dev/null +++ b/youchain-system/src/main/java/com/youchain/businessdata/service/impl/KMReServiceImpl.java @@ -0,0 +1,558 @@ +package com.youchain.businessdata.service.impl; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONArray; +import com.alibaba.fastjson.JSONObject; +import com.youchain.basicdata.domain.Point; +import com.youchain.basicdata.domain.Stock; +import com.youchain.basicdata.service.PointService; +import com.youchain.basicdata.service.StockService; +import com.youchain.businessdata.domain.AgvTask; +import com.youchain.businessdata.domain.Task; +import com.youchain.businessdata.service.*; +import com.youchain.exception.BadRequestException; +import com.youchain.modules.quartz.utils.TimeNumberUtils; +import com.youchain.modules.system.domain.Dict; +import com.youchain.modules.system.repository.DictRepository; +import com.youchain.utils.*; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.sql.Timestamp; +import java.util.*; + +@Service +@Slf4j +@RequiredArgsConstructor +public class KMReServiceImpl implements KMReService { + private final DictRepository dictRepository; + private final StockService stockService; + private final PointService pointService; + private final TaskService taskService; + private final AgvTaskService agvTaskService; + + + /** + * 容器入场Json + * + * @param containerCode 容器编号 + * @param position 点位 + */ + @Override + public String containerInJson(String containerCode, String position) { + JSONObject jsonObject = new JSONObject(true); + //请求 id + jsonObject.put("requestId", String.valueOf(System.currentTimeMillis())); + //容器类型 + jsonObject.put("containerType", ""); + //容器编号 + jsonObject.put("containerCode", containerCode); + //容器当前位置 + jsonObject.put("position", position); + //角度 + jsonObject.put("enterOrientation", ""); + return jsonObject.toString(); + } + + /** + * 容器入场 + * + * @param containerCode 容器 + * @param position 点位 + * @param itemCode 物料 + */ + @Override + @Transactional(rollbackFor = Exception.class) + public void containerIn(String containerCode, String position, String itemCode) { + //验证容器是否存在 + Stock stock = stockService.validateStock(containerCode); + + //验证点位是否存在 + Point point = pointService.validatePoint(position); + + //入空车 + this.handleEmptyContainer(stock, point); + + //下发任务 + this.sendAgvTaskToContainer(UrlApi.containerIn(), this.containerInJson(containerCode, position)); + } + + /** + * 容器出场Json + * + * @param containerCode 容器编号 + */ + @Override + public String containerOutJson(String containerCode) { + JSONObject jsonObject = new JSONObject(new LinkedHashMap<>()); + //请求 id + jsonObject.put("requestId", String.valueOf(System.currentTimeMillis())); + //容器类型 + jsonObject.put("containerType", ""); + //容器编号 + jsonObject.put("containerCode", containerCode); + //容器当前位置 + jsonObject.put("position", ""); + return jsonObject.toJSONString(); + } + + /** + * 容器出场 + * + * @param containerCode 容器 + */ + @Override + @Transactional(rollbackFor = Exception.class) + public void containerOut(String containerCode) { + //验证容器 + Stock stock = stockService.validateStock(containerCode); + + //释放点位 + Point point = stock.getPoint(); + if (point != null) { + pointService.freePoint(point); + } + + //释放容器 + stockService.usedStock(stock, null, BaseStatus.FREE); + + //下发任务 + this.sendAgvTaskToContainer(UrlApi.containerOut(), this.containerOutJson(containerCode)); + + } + + /** + * 入空车 + * + * @param stock 容器 + * @param point 点位 + */ + public void handleEmptyContainer(Stock stock, Point point) { + //占用点位 + pointService.usedPoint(point); + + //占用容器 + stockService.usedStock(stock, point, BaseStatus.FREE); + } + + + /** + * 下发容器入场或容器出场 + * + * @param url 接口地址 + * @param json 接口json + */ + @Override + public void sendAgvTaskToContainer(String url, String json) { + Dict dict = dictRepository.findDictByName("OPEN"); + if (dict != null) { + String resultJson = HttpPostUtil.sendPostReq(url, json); + if (StringUtils.isEmpty(resultJson)) { + throw new BadRequestException("AGV返回信息:接口调用失败!"); + } + JSONObject resultObject = JSON.parseObject(resultJson); + if (resultObject == null) { + throw new BadRequestException("AGV返回信息:接口数据返回为空!"); + } + String code = resultObject.getString("code"); + String message = resultObject.getString("message"); + if (!"0".equals(code)) { + throw new BadRequestException("AGV返回信息:接口调用失败!" + message); + } + } + + } + + /** + * 叉车任务Json + * + * @param agvTasks 任务 + */ + @Override + public String sendAgvTaskCcJson(AgvTask agvTasks) { + + JSONObject jsonObject = new JSONObject(true); + String requestId = TimeNumberUtils.getCcCode(); + Map objMap = new LinkedHashMap<>(); + objMap.put("orgId", "KUKA");//库存组织 ID + objMap.put("requestId", requestId);//请求 id + objMap.put("missionCode", agvTasks.getId());//任务编号 + objMap.put("missionType", agvTasks.getJobType());//货 架 ( 托 盘 ) 移动 RACK_MOVE + objMap.put("viewBoardType", "");// + objMap.put("containerCode", agvTasks.getStockCode());// + objMap.put("robotType", "FORKLIFT");//机器人功能类型 + objMap.put("robotId", "");//机器人编号 + objMap.put("priority", "1");//数值越小,优先级越高,默认是 1 + JSONArray missionDataArray = new JSONArray(); + JSONObject missionDataObj = new JSONObject(true); + Map missionDataMap = new LinkedHashMap<>(); + missionDataMap.put("sequence", 1);//序号 + missionDataMap.put("position", agvTasks.getStartSlotCode());//点位 + String nodeType = "NODE_POINT"; + if (BizStatus.PICK.equals(agvTasks.getType())) { + nodeType = "NODE_SLOT"; + } + missionDataMap.put("nodeType", nodeType);// + missionDataMap.put("stackNumber", 0); + missionDataMap.put("actionConfirm", false); + missionDataObj.putAll(missionDataMap); + missionDataArray.add(missionDataObj); + + JSONObject missionDataObj2 = new JSONObject(new LinkedHashMap<>()); + Map missionDataMap2 = new LinkedHashMap<>(); + missionDataMap2.put("sequence", 2);//序号 + missionDataMap2.put("position", agvTasks.getEndSlotCode());//目标点 + String nodeType2 = "NODE_SLOT"; + if (BizStatus.PICK.equals(agvTasks.getType())) { + nodeType2 = "NODE_POINT"; + } + missionDataMap2.put("nodeType", nodeType2);// + missionDataMap2.put("stackNumber", 0); + missionDataMap2.put("actionConfirm", false); + missionDataObj2.putAll(missionDataMap2); + missionDataArray.add(missionDataObj2); + + objMap.put("missionData", missionDataArray); + jsonObject.putAll(objMap); + return jsonObject.toJSONString(); + } + + /** + * 货架任务Json + * + * @param agvTasks 任务 + */ + @Override + public String sendAgvTaskHjJson(AgvTask agvTasks) { + JSONObject jsonObject = new JSONObject(true); + String requestId = TimeNumberUtils.getHjCode(); + Map objMap = new LinkedHashMap<>(); + objMap.put("orgId", "KUKA");//库存组织 ID + objMap.put("requestId", requestId);//请求 id + objMap.put("missionCode", agvTasks.getId());//任务编号 + objMap.put("missionType", agvTasks.getJobType());//货 架 ( 托 盘 ) 移动 RACK_MOVE + objMap.put("viewBoardType", "");//IDENTIFY_REQUIRE + objMap.put("robotType", "LIFT");//机器人功能类型 + objMap.put("priority", "1");//数值越小,优先级越高,默认是 1 + JSONArray missionDataArray = new JSONArray(); + JSONObject missionDataObj = new JSONObject(true); + Map missionDataMap = new LinkedHashMap<>(); + missionDataMap.put("sequence", 1);//序号 + missionDataMap.put("containerCode", agvTasks.getStockCode());//容器 + missionDataMap.put("startPosition", agvTasks.getStartSlotCode());//点位 + missionDataMap.put("startPositionType", "NODE_POINT");// + missionDataMap.put("endPosition", agvTasks.getEndSlotCode());//点位 + missionDataMap.put("endPositionType", "NODE_POINT");// + missionDataObj.putAll(missionDataMap); + missionDataArray.add(missionDataObj); + + objMap.put("missionData", missionDataArray); + jsonObject.putAll(objMap); + return jsonObject.toJSONString(); + } + + @Override + public String sendAgvTaskGtJson(AgvTask agvTask) { + JSONObject jsonObject = new JSONObject(true); + String requestId = TimeNumberUtils.getGTTaskCode(); + Map objMap = new LinkedHashMap<>(); + objMap.put("orgId", "KUKA");//库存组织 ID(或工厂代码,供应商代码) + objMap.put("requestId", requestId);//请求 id + objMap.put("missionCode", agvTask.getId());//任务编号 + objMap.put("missionType", "ROLLER_MOVE");//任务类型 :滚筒 + objMap.put("viewBoardType", "");//上视识别类型: + objMap.put("robotType", "ROLLER"); + objMap.put("priority", "1"); + objMap.put("lockRobotAfterFinish", false); + JSONArray missionDataArray = new JSONArray(); + + JSONObject missionDataObj = new JSONObject(true); + Map missionDataMap = new LinkedHashMap<>(); + missionDataMap.put("sequence", 1);//序号 + missionDataMap.put("position", agvTask.getStartSlotCode());//起点 + missionDataMap.put("type", "NODE_POINT");// + missionDataMap.put("actionType", "ROLLER_RECEIVE");// + missionDataMap.put("binCode", "");//容器 + missionDataMap.put("rollerLevel", 1);// + missionDataMap.put("deviceCode", agvTask.getStartSlotCode());//设备编号 + missionDataMap.put("actionConfirm", true);// + missionDataMap.put("passStrategy", "AUTO");// + missionDataObj.putAll(missionDataMap); + missionDataArray.add(missionDataObj); + + JSONObject missionDataObj2 = new JSONObject(true); + Map missionDataMap2 = new LinkedHashMap<>(); + missionDataMap2.put("sequence", 2);//序号 + missionDataMap2.put("position", "FX001");//中转点 + missionDataMap2.put("type", "NODE_POINT");// + missionDataMap2.put("actionType", "");// + missionDataMap2.put("binCode", "");//容器 + missionDataMap2.put("rollerLevel", 1);// + missionDataMap2.put("deviceCode", "");// + missionDataMap2.put("actionConfirm", false);// + missionDataMap2.put("passStrategy", "MANUAL");// + missionDataObj2.putAll(missionDataMap2); + missionDataArray.add(missionDataObj2); + + JSONObject missionDataObj3 = new JSONObject(true); + Map missionDataMap3 = new LinkedHashMap<>(); + missionDataMap3.put("sequence", 3);//序号 + missionDataMap3.put("position", agvTask.getEndSlotCode());//终点 + missionDataMap3.put("type", "NODE_POINT");// + missionDataMap3.put("actionType", "ROLLER_SEND");// + missionDataMap3.put("binCode", "");//容器 + missionDataMap3.put("rollerLevel", 1);// + missionDataMap3.put("deviceCode", agvTask.getEndSlotCode());//终点 + missionDataMap3.put("actionConfirm", true);// + missionDataMap3.put("passStrategy", "AUTO");// + missionDataObj3.putAll(missionDataMap3); + missionDataArray.add(missionDataObj3); + + objMap.put("missionData", missionDataArray); + jsonObject.putAll(objMap); + return jsonObject.toJSONString(); + } + + @Override + public String sendAgvTaskQYCJson(AgvTask agvTask, List tugModels) { + JSONObject jsonObject = new JSONObject(true); + String requestId = TimeNumberUtils.getGTTaskCode(); + Map objMap = new LinkedHashMap<>(); + objMap.put("orgId", "KUKA");//库存组织 ID(或工厂代码,供应商代码) + objMap.put("requestId", requestId);//请求 id + objMap.put("missionCode", agvTask.getId());//任务编号 + objMap.put("missionType", "TUGGER_MOVE");//任务类型 :滚筒 + objMap.put("viewBoardType", "");//上视识别类型: + objMap.put("robotType", "TUGGER"); + objMap.put("priority", "1"); + objMap.put("templateCode", ""); + objMap.put("lockRobotAfterFinish", false); + objMap.put("unlockRobotId", ""); + objMap.put("unlockMissionCode", ""); + + JSONArray missionDataArray = new JSONArray(); + + JSONObject missionDataObj = new JSONObject(true); + Map missionDataMap = new LinkedHashMap<>(); + missionDataMap.put("sequence", 1);//序号 + missionDataMap.put("type", "NODE_POINT");//作业类型:点位:NODE_POINT;区域:NODE_AREA + missionDataMap.put("position", agvTask.getStartSlotCode());//起点 + missionDataMap.put("actionType", "TUGGER_ATTACH");//动作:TUGGER_ATTACH:挂钩;TUGGER_DETACH:脱钩 + missionDataMap.put("tugCount", tugModels.size());//牵引车后方的拖挂车数量 + missionDataMap.put("passStrategy", "MANUAL");//当前任务点结束后放行策略:自动:AUTO;手动:MANUAL + missionDataMap.put("tugModels", tugModels);//牵引车后方的拖挂车规格【模型名字】需要和tugCount一致 + missionDataObj.putAll(missionDataMap); + missionDataArray.add(missionDataObj); + + JSONObject missionDataObj2 = new JSONObject(true); + Map missionDataMap2 = new LinkedHashMap<>(); + missionDataMap2.put("sequence", 2);//序号 + missionDataMap2.put("type", "NODE_AREA");//作业类型:点位:NODE_POINT;区域:NODE_AREA + missionDataMap2.put("position", agvTask.getEndSlotCode());//终点 + missionDataMap.put("actionType", "TUGGER_DETACH");//动作:TUGGER_ATTACH:挂钩;TUGGER_DETACH:脱钩 + missionDataMap.put("passStrategy", "AUTO");//当前任务点结束后放行策略:自动:AUTO;手动:MANUAL + missionDataMap2.put("waitingMillis", 0);//自动触发离开当前任务节点的时间,默认单位:毫秒 + missionDataObj2.putAll(missionDataMap2); + missionDataArray.add(missionDataObj2); + + objMap.put("missionData", missionDataArray); + jsonObject.putAll(objMap); + return jsonObject.toJSONString(); + } + + @Override + public void sendAgvTask(AgvTask agvTasks, String json) { + Dict dict = dictRepository.findDictByName("OPEN"); + String resultJson = ""; + if (dict != null) { + resultJson = HttpPostUtil.sendPostReq(UrlApi.submitMission(), json); + if (StringUtils.isEmpty(resultJson)) { + throw new BadRequestException("AGV返回信息:下发任务接口调用失败!"); + } + JSONObject resulObject = JSON.parseObject(resultJson); + if (resulObject == null) { + throw new BadRequestException("AGV返回信息:下发任务接口返回为空!"); + } + + String code = resulObject.getString("code"); + String message = resulObject.getString("message"); + if (!"0".equals(code)) { + throw new BadRequestException("AGV返回消息:" + message); + } + } + + agvTasks.setJobForce(agvTasks.getId().toString()); + agvTasks.setJobForceAsc((1)); + agvTasks.setStatus(BizStatus.ATCALL); + agvTasks.setJobMessage(resultJson); + agvTasks.setReqMessage(json); + agvTasks.setStartTime(new Timestamp(System.currentTimeMillis())); + agvTaskService.update(agvTasks); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void missionStateCallback(AgvTask agvTask, String status, String containerCode, String currentPosition) { + Stock stock = stockService.validateStock(containerCode); + //顶升的是起点;其它终点; + Point point; + String pointCode; + if ("UP_CONTAINER".equals(status) || "FORK_UP".equals(status)) { + pointCode = agvTask.getStartSlotCode(); + } else { + pointCode = agvTask.getEndSlotCode(); + } + point = pointService.queryPoint(pointCode, null, null, null); + switch (status) { + case "UP_CONTAINER": + case "FORK_UP": + handleUpContainer(agvTask, stock, point);//容器顶升 + break; + case "FORK_DOWN": + //容器放下 + break; + case "ARRIVED": + //容器到达 + break; + case "COMPLETED": + handleComContainer(agvTask, stock, point);//任务完成 + break; + case "CANCELED": + handleCanceledTask(agvTask, stock, point);//任务取消 + break; + case "RESEND": + handleResendTask(agvTask);//重新发送 + break; + } + + } + + @Override + public String operationFeedbackJson(AgvTask agvTask) { + JSONObject jsonObject = new JSONObject(new LinkedHashMap<>()); + //请求 id + jsonObject.put("requestId", String.valueOf(System.currentTimeMillis())); + //容器类型 + jsonObject.put("containerCode", ""); + //容器编号 + jsonObject.put("missionCode", agvTask.getId()); + //容器当前位置 + jsonObject.put("position", ""); + return jsonObject.toString(); + } + + /** + * 容器顶升 + * + * @param agvTask 任务 + * @param stock 容器 + */ + private void handleUpContainer(AgvTask agvTask, Stock stock, Point startPoint) { + //顶升,起点释放点位 + pointService.freePoint(startPoint); + agvTask.setStockCode(stock == null ? null : stock.getCode()); + agvTask.setStatus(BizStatus.UP_CONTAINER); + agvTaskService.update(agvTask); + } + + /** + * 任务完成 + * + * @param agvTask 任务 + * @param stock 容器 + */ + private void handleComContainer(AgvTask agvTask, Stock stock, Point endPoint) { + //任务完成;根据AGV任务的目标点位走对应流程 + switch (agvTask.getType()) { + case BizStatus.PICK: + break; + case BizStatus.ASN: + break; + default: + throw new BadRequestException("任务类型不存在!"); + } + + //更新任务状态 + this.updateAgvTaskStatus(agvTask, stock, BizStatus.FINISH); + + } + + /** + * 任务取消完成 + * + * @param agvTask 任务 + * @param stock 容器 + */ + private void handleCanceledTask(AgvTask agvTask, Stock stock, Point endPoint) { + + //更新任务状态 + this.updateAgvTaskStatus(agvTask, stock, BizStatus.CANCEL); + + } + + /** + * 重新发送任务 + * + * @param agvTask 任务 + */ + private synchronized void handleResendTask(AgvTask agvTask) { + Boolean bool = agvTaskService.isAGVTaskDuplicate(agvTask.getStockCode(), agvTask.getStartSlotCode(), agvTask.getEndSlotCode()); + if (bool) { + throw new BadRequestException("任务已重新生成,请勿重复操作! "); + } + AgvTask newAgvTask = AgvTask.builder() + .stockCode(agvTask.getStockCode()) + .type(agvTask.getType()) + .jobType(agvTask.getJobType()) + .jobPriority(1) + .startSlotCode(agvTask.getStartSlotCode()) + .endSlotCode(agvTask.getEndSlotCode()) + .slotCode(agvTask.getSlotCode()) + .status(BizStatus.OPEN) + .lineSlotCode(agvTask.getLineSlotCode()) + .build(); + agvTaskService.create(newAgvTask); + + List taskList = new ArrayList<>(); + + for (Task task : taskList) { + task.setAgvTask(newAgvTask); + taskService.update(task); + } + + + // 根据任务类型发送不同的实现 + switch (agvTask.getJobType()) { + case "FORKLIFT_MOVE": + sendAgvTask(newAgvTask, sendAgvTaskCcJson(newAgvTask)); + break; + case "RACK_MOVE": + sendAgvTask(newAgvTask, sendAgvTaskHjJson(newAgvTask)); + break; + case "ROLLER_MOVE": + sendAgvTask(newAgvTask, sendAgvTaskGtJson(newAgvTask)); + break; + default: + throw new BadRequestException("任务类型不支持: " + agvTask.getJobType()); + } + + + } + + + /** + * 更新任务状态 + * + * @param agvTask 任务 + * @param stock 容器 + * @param status 状态 + */ + private void updateAgvTaskStatus(AgvTask agvTask, Stock stock, String status) { + agvTask.setStockCode(stock == null ? null : stock.getCode()); + agvTask.setStatus(status); + agvTask.setEndTime(new Timestamp(new Date().getTime())); + agvTaskService.update(agvTask); + } +} diff --git a/youchain-system/src/main/java/com/youchain/businessdata/service/impl/LesServiceImpl.java b/youchain-system/src/main/java/com/youchain/businessdata/service/impl/LesServiceImpl.java index 8c9bc7e..70a4e24 100644 --- a/youchain-system/src/main/java/com/youchain/businessdata/service/impl/LesServiceImpl.java +++ b/youchain-system/src/main/java/com/youchain/businessdata/service/impl/LesServiceImpl.java @@ -1,14 +1,20 @@ package com.youchain.businessdata.service.impl; +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import com.youchain.businessdata.domain.AgvTask; import com.youchain.businessdata.domain.Les; import com.youchain.businessdata.inputJson.LesRequest; import com.youchain.businessdata.inputJson.PositionCodeRequest; import com.youchain.businessdata.repository.LesRepository; +import com.youchain.businessdata.service.KMReService; import com.youchain.businessdata.service.LesService; import com.youchain.businessdata.service.dto.LesDto; import com.youchain.businessdata.service.dto.LesQueryCriteria; import com.youchain.businessdata.service.mapstruct.LesMapper; import com.youchain.exception.BadRequestException; +import com.youchain.modules.system.domain.Dict; +import com.youchain.modules.system.repository.DictRepository; import com.youchain.utils.*; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; @@ -19,6 +25,8 @@ import org.springframework.transaction.annotation.Transactional; import javax.servlet.http.HttpServletResponse; import java.io.IOException; +import java.sql.Timestamp; +import java.text.SimpleDateFormat; import java.util.*; @Service @@ -28,6 +36,8 @@ public class LesServiceImpl implements LesService { private final LesRepository lesRepository; + private final DictRepository dictRepository; + private final LesMapper lesMapper; @Override @@ -97,8 +107,7 @@ public class LesServiceImpl implements LesService { validateParams(lesRequest); //验证任务是否存在 - String taskCode = lesRequest.getTaskCode(); - validateLes(taskCode); + validateLes(lesRequest.getTaskCode()); String materialCode = lesRequest.getMaterialCode();//物料代码 @@ -107,9 +116,36 @@ public class LesServiceImpl implements LesService { createLes(lesRequest); } else { //直接转发给AGV + sendLesTask(JSON.toJSONString(lesRequest)); } } + @Override + public String lesCallBack(String currentPositionCode,String taskCode) { + JSONObject jsonObject = new JSONObject(true); + String guid = String.valueOf(System.currentTimeMillis()); + //LES任务的业务单号,不一定唯一 + jsonObject.put("reqCode", guid); + //请求 id + jsonObject.put("guid", guid); + //系统标识 + jsonObject.put("appId", "KUKA"); + //请求时间 + SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + jsonObject.put("reqTime", sdf.format(new Date())); + //当前点位 + jsonObject.put("currentPositionCode", currentPositionCode); + //关联任务号 + jsonObject.put("relReqTask", ""); + //备注 + jsonObject.put("data", ""); + //LES产生的任务号 + jsonObject.put("taskCode", taskCode); + //method + jsonObject.put("method", "end"); + return jsonObject.toString(); + } + /** * 验证参数有效性 * @@ -117,10 +153,23 @@ public class LesServiceImpl implements LesService { */ private void validateParams(LesRequest lesRequest) { if (StringUtils.isEmpty(lesRequest.getTaskCode())) { - throw new BadRequestException("任务号必填!"); + throw new BadRequestException("taskCode必填"); } + //物料有值;说明是料箱上线场景 if (StringUtils.isNotEmpty(lesRequest.getMaterialCode())) { - if (lesRequest.getPositionCodes().isEmpty() || lesRequest.getPositionCodes().size() < 2) { + if(StringUtils.isEmpty(lesRequest.getRouteCode())){ + throw new BadRequestException("routeCode必填"); + } + + if(StringUtils.isEmpty(lesRequest.getBoxNo())){ + throw new BadRequestException("boxNo必填"); + } + + if(StringUtils.isEmpty(lesRequest.getOnlineNo())){ + throw new BadRequestException("onlineNo必填"); + } + + if (lesRequest.getPositionCodePath()==null ||lesRequest.getPositionCodePath().isEmpty() || lesRequest.getPositionCodePath().size() < 2) { throw new BadRequestException("节点不能为空且长度至少为2"); } } @@ -134,14 +183,14 @@ public class LesServiceImpl implements LesService { private void validateLes(String taskCode) { Les les = lesRepository.findByTaskCode(taskCode); if (les != null) { - throw new BadRequestException(taskCode + "任务号已存在!"); + throw new BadRequestException(taskCode + "任务号系统已接收,请勿重复请求"); } } @Transactional(rollbackFor = Exception.class) public void createLes(LesRequest lesRequest) { //节点集合 - List positionCodes = lesRequest.getPositionCodes(); + List positionCodes = lesRequest.getPositionCodePath(); //起点对象 PositionCodeRequest srcPosition = positionCodes.get(0); //终点对象 @@ -162,4 +211,25 @@ public class LesServiceImpl implements LesService { lesRepository.save(les); } + private void sendLesTask(String json) { + Dict dict = dictRepository.findDictByName("OPEN"); + String resultJson = ""; + if (dict != null) { + resultJson = HttpPostUtil.sendPostReq(UrlApi.submitMission(), json); + if (StringUtils.isEmpty(resultJson)) { + throw new BadRequestException("AGV返回信息:下发任务接口调用失败"); + } + JSONObject resulObject = JSON.parseObject(resultJson); + if (resulObject == null) { + throw new BadRequestException("AGV返回信息:下发任务接口返回为空"); + } + + String code = resulObject.getString("code"); + String message = resulObject.getString("message"); + if (!"0".equals(code)) { + throw new BadRequestException("AGV返回消息:" + message); + } + } + } + } diff --git a/youchain-system/src/main/java/com/youchain/businessdata/service/mapstruct/LesMapper.java b/youchain-system/src/main/java/com/youchain/businessdata/service/mapstruct/LesMapper.java index ab64efc..cf707d1 100644 --- a/youchain-system/src/main/java/com/youchain/businessdata/service/mapstruct/LesMapper.java +++ b/youchain-system/src/main/java/com/youchain/businessdata/service/mapstruct/LesMapper.java @@ -1,9 +1,7 @@ package com.youchain.businessdata.service.mapstruct; import com.youchain.base.BaseMapper; -import com.youchain.businessdata.domain.AgvTask; import com.youchain.businessdata.domain.Les; -import com.youchain.businessdata.service.dto.AgvTaskDto; import com.youchain.businessdata.service.dto.LesDto; import org.mapstruct.Mapper; import org.mapstruct.ReportingPolicy; diff --git a/youchain-system/src/main/java/com/youchain/modules/quartz/utils/TimeNumberUtils.java b/youchain-system/src/main/java/com/youchain/modules/quartz/utils/TimeNumberUtils.java index a1df986..bd50b03 100644 --- a/youchain-system/src/main/java/com/youchain/modules/quartz/utils/TimeNumberUtils.java +++ b/youchain-system/src/main/java/com/youchain/modules/quartz/utils/TimeNumberUtils.java @@ -5,7 +5,7 @@ import java.util.Date; public class TimeNumberUtils { private static int sequence = 0; - private static int length = 5; + private static final int length = 5; public static synchronized String getCKCode() { sequence = sequence >= 999999 ? 1 : sequence + 1; @@ -23,20 +23,20 @@ public class TimeNumberUtils { return "RK"+datetime +addLeftZero(s, length); } - public static synchronized String getRCCode() { + public static synchronized String getCcCode() { sequence = sequence >= 999999 ? 1 : sequence + 1; String datetime = new SimpleDateFormat("yyMMddHHmmss") .format(new Date()); String s = Integer.toString(sequence); - return "RC"+datetime +addLeftZero(s, length); + return "CC"+datetime +addLeftZero(s, length); } - public static synchronized String getXJTaskCode() { + public static synchronized String getHjCode() { sequence = sequence >= 999999 ? 1 : sequence + 1; String datetime = new SimpleDateFormat("yyMMddHHmmss") .format(new Date()); String s = Integer.toString(sequence); - return "XJ"+datetime +addLeftZero(s, length); + return "HJ"+datetime +addLeftZero(s, length); } public static synchronized String getGTTaskCode() { @@ -47,13 +47,6 @@ public class TimeNumberUtils { return "GT"+datetime +addLeftZero(s, length); } - public static synchronized String getKLXTaskCode() { - sequence = sequence >= 999999 ? 1 : sequence + 1; - String datetime = new SimpleDateFormat("yyMMddHHmmss") - .format(new Date()); - String s = Integer.toString(sequence); - return "KLX"+datetime +addLeftZero(s, length); - } /** * 左填0 diff --git a/youchain-system/src/main/java/com/youchain/modules/system/repository/DictRepository.java b/youchain-system/src/main/java/com/youchain/modules/system/repository/DictRepository.java index fef6525..3c7c3f1 100644 --- a/youchain-system/src/main/java/com/youchain/modules/system/repository/DictRepository.java +++ b/youchain-system/src/main/java/com/youchain/modules/system/repository/DictRepository.java @@ -42,9 +42,6 @@ public interface DictRepository extends JpaRepository, JpaSpecificat */ List findByIdIn(Set ids); - @Query(value = "SELECT * FROM sys_dict b WHERE b.name = ?1 ", nativeQuery = true) - Dict getDictDescription(String name); - - @Query(value = " from Dict where description = :description ") - Dict findDictByDescription(String description); + @Query("from Dict dict where dict.name = :name ") + Dict findDictByName(String name); } diff --git a/youchain-system/src/main/java/com/youchain/modules/system/service/DictService.java b/youchain-system/src/main/java/com/youchain/modules/system/service/DictService.java index 02a6835..7cfcbfe 100644 --- a/youchain-system/src/main/java/com/youchain/modules/system/service/DictService.java +++ b/youchain-system/src/main/java/com/youchain/modules/system/service/DictService.java @@ -73,5 +73,5 @@ public interface DictService { */ void download(List queryAll, HttpServletResponse response) throws IOException; - Dict getDictDescription(String name); + Dict findDictByName(String name); } \ No newline at end of file diff --git a/youchain-system/src/main/java/com/youchain/modules/system/service/impl/DictServiceImpl.java b/youchain-system/src/main/java/com/youchain/modules/system/service/impl/DictServiceImpl.java index 774721c..1aeb089 100644 --- a/youchain-system/src/main/java/com/youchain/modules/system/service/impl/DictServiceImpl.java +++ b/youchain-system/src/main/java/com/youchain/modules/system/service/impl/DictServiceImpl.java @@ -26,6 +26,7 @@ import lombok.RequiredArgsConstructor; import com.youchain.modules.system.repository.DictRepository; import com.youchain.modules.system.service.mapstruct.DictMapper; import org.springframework.cache.annotation.CacheConfig; +import org.springframework.cache.annotation.Cacheable; import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; import org.springframework.stereotype.Service; @@ -116,8 +117,9 @@ public class DictServiceImpl implements DictService { } @Override - public Dict getDictDescription(String name) { - return dictRepository.getDictDescription(name); + @Cacheable(key = "#name", unless = "#result == null") + public Dict findDictByName(String name) { + return dictRepository.findDictByName(name); } public void delCaches(Dict dict){