src/main/java/com/zy/asrs/controller/ShuttleController.java
@@ -368,6 +368,10 @@ //演示模式-关 shuttleThread.enableDemo(false); return R.ok(); } else if (shuttleTaskModeType == ShuttleTaskModeType.CLEAR_PATH) { //清除路径 shuttleAction.clearPath(shuttleProtocol.getShuttleNo()); return R.ok(); } else { throw new CoolException("未知命令"); } src/main/java/com/zy/asrs/controller/TrafficControlController.java
New file @@ -0,0 +1,63 @@ package com.zy.asrs.controller; import com.alibaba.fastjson.JSON; import com.baomidou.mybatisplus.mapper.EntityWrapper; import com.core.common.R; import com.zy.asrs.domain.param.CancelTrafficParam; import com.zy.asrs.entity.WrkMast; import com.zy.asrs.service.WrkMastService; import com.zy.common.model.NavigateNode; import com.zy.common.utils.RedisUtil; import com.zy.core.cache.SlaveConnection; import com.zy.core.enums.RedisKeyType; import com.zy.core.enums.ShuttleCommandModeType; import com.zy.core.enums.SlaveType; import com.zy.core.model.TrafficControlDataModel; import com.zy.core.model.command.ShuttleCommand; import com.zy.core.thread.TrafficControlThread; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RestController; import java.util.List; @Slf4j @RestController public class TrafficControlController { @Autowired private RedisUtil redisUtil; @Autowired private WrkMastService wrkMastService; @GetMapping("/trafficControl/getTrafficControlInfos") public R getTrafficControlInfos() { Object object = redisUtil.get(RedisKeyType.TRAFFIC_CONTROL_MAP.key); if (object == null) { return R.ok(); } List<TrafficControlDataModel> trafficControlDataList = (List<TrafficControlDataModel>) object; for (TrafficControlDataModel dataModel : trafficControlDataList) { WrkMast wrkMast = wrkMastService.selectOne(new EntityWrapper<WrkMast>() .eq("wrk_no", dataModel.getTaskNo())); dataModel.setTaskExist(wrkMast != null); } return R.ok().add(trafficControlDataList); } @PostMapping("/trafficControl/cancelTraffic") public R cancelTraffic(CancelTrafficParam param) { TrafficControlThread trafficControlThread = (TrafficControlThread) SlaveConnection.get(SlaveType.TrafficControl, 1); if (trafficControlThread == null) { return R.error(); } boolean result = trafficControlThread.cancelTrafficControl(param.getShuttleNo(), param.getTaskNo()); return R.ok().add(result); } } src/main/java/com/zy/asrs/domain/param/CancelTrafficParam.java
New file @@ -0,0 +1,12 @@ package com.zy.asrs.domain.param; import lombok.Data; @Data public class CancelTrafficParam { private Integer shuttleNo; private Integer taskNo; } src/main/java/com/zy/asrs/service/impl/MainServiceImpl.java
@@ -494,6 +494,10 @@ return false; } if (shuttleProtocol.getCurrentLocNo() == null) { return false; } if (!shuttleProtocol.getCurrentLocNo().equals(wrkMast.getSourceLocNo())) { News.taskInfo(wrkMast.getWrkNo(), "{}任务,小车未到达取货位置", wrkMast.getWrkNo(), wrkMast.getSourceLocNo()); return false; src/main/java/com/zy/common/utils/NavigateMapUtils.java
@@ -2,13 +2,18 @@ import com.zy.asrs.utils.Utils; import com.zy.common.model.NavigateNode; import com.zy.core.cache.SlaveConnection; import com.zy.core.enums.RedisKeyType; import com.zy.core.enums.SlaveType; import com.zy.core.model.protocol.ShuttleProtocol; import com.zy.core.thread.ShuttleThread; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; @Component public class NavigateMapUtils { @@ -16,6 +21,39 @@ @Autowired private RedisUtil redisUtil; public synchronized boolean clearPath(Integer shuttleNo) { ShuttleThread shuttleThread = (ShuttleThread) SlaveConnection.get(SlaveType.Shuttle, shuttleNo); if (shuttleThread == null) { return false; } ShuttleProtocol shuttleProtocol = shuttleThread.getStatus(); if (shuttleProtocol == null) { return false; } String currentLocNo = shuttleProtocol.getCurrentLocNo(); int lev = Utils.getLev(currentLocNo); HashMap<String, Object> lockMap = new HashMap<>(); Object o = redisUtil.get(RedisKeyType.LOCK_MAP_NODES.key + lev); if (o != null) { lockMap = (HashMap<String, Object>) o; } List<NavigateNode> list = new ArrayList<>(); for (Map.Entry<String, Object> entry : lockMap.entrySet()) { String locNo = entry.getKey(); Integer value = (Integer) entry.getValue(); if (value.equals(shuttleNo)) { NavigateNode navigateNode = NavigatePositionConvert.locNoToNode(locNo); list.add(navigateNode); } } return writeNavigateNodeToRedisMap(lev, shuttleNo, list, false); } /** * 写入路径节点数据到redis地图中 * lock为true 禁用库位,lock为false恢复库位 src/main/java/com/zy/common/utils/RedisUtil.java
@@ -136,6 +136,24 @@ try { redisTemplate.opsForValue().set(key, value); redisTemplate.execute((RedisCallback<Void>) connection -> null); return true; } catch (Exception e) { e.printStackTrace(); return false; } } /** * 普通缓存放入 * * @param key 键 * @param value 值 * @return true成功 false失败 */ public boolean setSync(String key, Object value) { try { redisTemplate.opsForValue().set(key, value); redisTemplate.execute((RedisCallback<Void>) connection -> null); long start = System.currentTimeMillis(); while (System.currentTimeMillis() - start < 10000) {//有效期10s Object o = redisTemplate.opsForValue().get(key); src/main/java/com/zy/core/ServerBootstrap.java
@@ -8,9 +8,11 @@ import com.zy.asrs.service.BasLiftService; import com.zy.asrs.service.DeviceConfigService; import com.zy.common.utils.RedisUtil; import com.zy.core.action.ShuttleAction; import com.zy.core.cache.MessageQueue; import com.zy.core.cache.SlaveConnection; import com.zy.core.enums.SlaveType; import com.zy.core.task.ShuttleExecuteScheduler; import com.zy.core.thread.TrafficControlThread; import com.zy.core.thread.impl.NyShuttleThread; import com.zy.core.thread.impl.TrafficControlImplThread; @@ -18,6 +20,7 @@ import com.zy.core.utils.DeviceMsgUtils; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.scheduling.annotation.Async; import org.springframework.stereotype.Component; @@ -33,12 +36,17 @@ @Component public class ServerBootstrap { @Value("${deviceExecuteConfig.threadControlCount}") private int threadControlCount; @Autowired private MainProcess mainProcess; @Autowired private RedisUtil redisUtil; @Autowired private DeviceConfigService deviceConfigService; @Autowired private ShuttleAction shuttleAction; @Autowired private DeviceMsgUtils deviceMsgUtils; @Autowired @@ -136,6 +144,9 @@ TrafficControlThread trafficControlThread = new TrafficControlImplThread(redisUtil); new Thread(trafficControlThread).start(); SlaveConnection.put(SlaveType.TrafficControl, 1, trafficControlThread); ShuttleExecuteScheduler shuttleExecuteScheduler = new ShuttleExecuteScheduler(shuttleAction, deviceConfigService, redisUtil, threadControlCount); new Thread(shuttleExecuteScheduler).start(); } src/main/java/com/zy/core/action/ShuttleAction.java
@@ -119,8 +119,10 @@ return false; } News.info("execute check command {},{}", shuttleNo, taskNo); //检测命令 int checked = checkCommand(redisCommand, shuttleNo); News.info("execute check command complete {},{}", shuttleNo, taskNo); if (checked == 0) { return false; } @@ -165,10 +167,20 @@ } List<NavigateNode> nodes = JSON.parseArray(JSON.toJSONString(command.getNodes()), NavigateNode.class); //申请管制 applyTrafficControl(commands, nodes, shuttleNo, taskNo); Object object = redisUtil.get(RedisKeyType.TRAFFIC_CONTROL_LOCK_APPLY.key + shuttleNo); if (object == null) { //申请管制 News.info("execute apply control {},{}", shuttleNo, taskNo); redisUtil.set(RedisKeyType.TRAFFIC_CONTROL_LOCK_APPLY.key + shuttleNo, "lock", 10); applyTrafficControl(commands, nodes, shuttleNo, taskNo); News.info("execute apply control complete {},{}", shuttleNo, taskNo); } News.info("execute query control {},{}", shuttleNo, taskNo); //查询管制 boolean apply = queryTrafficControl(shuttleNo, taskNo); News.info("execute query control complete {},{}", shuttleNo, taskNo); if(!apply){ return false;//申请失败 } @@ -415,7 +427,9 @@ return false; } //上报交管 News.info("execute check command report traffic {},{}", shuttleNo, shuttleProtocol.getTaskNo()); trafficControlThread.trafficReport(command.getNodesDeepCopy(), shuttleNo, shuttleProtocol.getTaskNo()); News.info("execute check command report traffic complete {},{}", shuttleNo, shuttleProtocol.getTaskNo()); String currentLocNo = shuttleProtocol.getCurrentLocNo(); if (currentLocNo == null) { @@ -768,6 +782,10 @@ } } public synchronized boolean clearPath(Integer shuttleNo) { return navigateMapUtils.clearPath(shuttleNo); } // //跑库程序 // public synchronized void moveLoc(Integer shuttleNo) { // ShuttleThread shuttleThread = (ShuttleThread) SlaveConnection.get(SlaveType.Shuttle, shuttleNo); src/main/java/com/zy/core/enums/RedisKeyType.java
@@ -19,6 +19,10 @@ //交管信息 TRAFFIC_CONTROL_MAP("traffic_control_map"), TRAFFIC_CONTROL_APPLY("traffic_control_apply_"), TRAFFIC_CONTROL_REPORT_LIST("traffic_control_report_list_"), TRAFFIC_CONTROL_LOCK_APPLY("traffic_control_lock_apply_"), TRAFFIC_CONTROL_SHUTTLE_APPLY_COUNT("traffic_control_shuttle_apply_count_"), //地图锁定节点 LOCK_MAP_NODES("lock_map_nodes_"), src/main/java/com/zy/core/enums/ShuttleTaskModeType.java
@@ -19,6 +19,7 @@ UPDATE_LOCATION(14, "更新坐标"), CHARGE_ON(15, "充电-开"), CHARGE_OFF(16, "充电-关"), CLEAR_PATH(17, "清除路径"), ; public Integer id; src/main/java/com/zy/core/model/TrafficControlDataModel.java
@@ -16,4 +16,19 @@ private List<NavigateNode> totalNodeList; private Integer applyCount = 0; private Boolean taskExist; public TrafficControlDataModel() { } public TrafficControlDataModel(Integer shuttleNo, Integer taskNo, List<NavigateNode> nodeList, List<NavigateNode> totalNodeList) { this.shuttleNo = shuttleNo; this.taskNo = taskNo; this.nodeList = nodeList; this.totalNodeList = totalNodeList; } } src/main/java/com/zy/core/model/param/OperateTrafficControlParam.java
New file @@ -0,0 +1,20 @@ package com.zy.core.model.param; import com.zy.common.model.NavigateNode; import com.zy.core.model.TrafficControlDataModel; import lombok.Data; import java.util.List; @Data public class OperateTrafficControlParam { private TrafficControlDataModel dataModel; private String operaType; private Boolean forceCancel; private List<NavigateNode> reportNodeList; } src/main/java/com/zy/core/task/ShuttleExecuteScheduler.java
@@ -4,43 +4,81 @@ import com.zy.asrs.entity.DeviceConfig; import com.zy.asrs.service.DeviceConfigService; import com.zy.common.utils.RedisUtil; import com.zy.core.News; import com.zy.core.action.ShuttleAction; import com.zy.core.enums.RedisKeyType; import com.zy.core.enums.SlaveType; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Component; import java.util.ArrayList; import java.util.List; @Slf4j @Component public class ShuttleExecuteScheduler { public class ShuttleExecuteScheduler implements Runnable { // @Autowired // private ShuttleAction shuttleAction; // @Autowired // private DeviceConfigService deviceConfigService; // @Autowired // private RedisUtil redisUtil; // // @Scheduled(cron = "0/1 * * * * ? ") // public void execute() { // List<DeviceConfig> shuttleList = deviceConfigService.selectList(new EntityWrapper<DeviceConfig>() // .eq("device_type", String.valueOf(SlaveType.Shuttle))); // for (DeviceConfig deviceConfig : shuttleList) { // Object object = redisUtil.get(RedisKeyType.SHUTTLE_FLAG.key + deviceConfig.getDeviceNo()); // if (object == null) { // continue; // } // // int taskNo = Integer.parseInt(String.valueOf(object)); // if (taskNo != 0) { // //存在任务需要执行 // boolean result = shuttleAction.executeWork(deviceConfig.getDeviceNo(), taskNo); // } // } // } private ShuttleAction shuttleAction; private DeviceConfigService deviceConfigService; private RedisUtil redisUtil; private int threadControlCount; @Scheduled(cron = "0/1 * * * * ? ") public void execute() { } public ShuttleExecuteScheduler(ShuttleAction shuttleAction, DeviceConfigService deviceConfigService, RedisUtil redisUtil, int threadControlCount) { this.shuttleAction = shuttleAction; this.deviceConfigService = deviceConfigService; this.redisUtil = redisUtil; this.threadControlCount = threadControlCount; } @Override public void run() { List<DeviceConfig> shuttleList = deviceConfigService.selectList(new EntityWrapper<DeviceConfig>() .eq("device_type", String.valueOf(SlaveType.Shuttle))); List<List<DeviceConfig>> lists = new ArrayList<>(); List<DeviceConfig> tmp = new ArrayList<>(); for (int i = 0; i < shuttleList.size(); i++) { DeviceConfig deviceConfig = shuttleList.get(i); if (i != 0 && i % threadControlCount == 0) { lists.add(tmp); tmp = new ArrayList<>(); } tmp.add(deviceConfig); } lists.add(tmp); for (List<DeviceConfig> list : lists) { if (list.isEmpty()) { continue; } new Thread(() -> { while (true) { try { for (DeviceConfig deviceConfig : list) { Object object = redisUtil.get(RedisKeyType.SHUTTLE_FLAG.key + deviceConfig.getDeviceNo()); if (object == null) { continue; } int taskNo = Integer.parseInt(String.valueOf(object)); if (taskNo != 0) { //存在任务需要执行 long startTime = System.currentTimeMillis(); News.info("execute {},{}", deviceConfig.getDeviceNo(), taskNo); boolean result = shuttleAction.executeWork(deviceConfig.getDeviceNo(), taskNo); Thread.sleep(100); News.info("execute end {},{},{}", deviceConfig.getDeviceNo(), taskNo, System.currentTimeMillis() - startTime); } } }catch (Exception e){ e.printStackTrace(); } } }).start(); } } } src/main/java/com/zy/core/task/TrafficApplyProcess.java
New file @@ -0,0 +1,104 @@ package com.zy.core.task; import com.zy.common.utils.RedisUtil; import com.zy.core.cache.SlaveConnection; import com.zy.core.enums.RedisKeyType; import com.zy.core.enums.SlaveType; import com.zy.core.model.TrafficControlDataModel; import com.zy.core.model.param.OperateTrafficControlParam; import com.zy.core.thread.TrafficControlThread; import lombok.Getter; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Component; import java.util.ArrayList; import java.util.Comparator; import java.util.List; import java.util.Set; @Slf4j @Component public class TrafficApplyProcess { @Autowired private RedisUtil redisUtil; @Scheduled(cron = "0/3 * * * * ? ") public void processApply() { TrafficControlThread trafficControlThread = (TrafficControlThread) SlaveConnection.get(SlaveType.TrafficControl, 1); if (trafficControlThread == null) { return; } Set<String> keys = redisUtil.searchKeys(RedisKeyType.TRAFFIC_CONTROL_APPLY.key); List<ApplyKey> sortList = new ArrayList<>(); for (String key : keys) { String[] split = key.split(RedisKeyType.TRAFFIC_CONTROL_APPLY.key); String[] split1 = split[1].split("_"); String shuttleNo = split1[0]; int count = 0; String applyCountKey = RedisKeyType.TRAFFIC_CONTROL_SHUTTLE_APPLY_COUNT.key + shuttleNo; Object object = redisUtil.get(applyCountKey); if(object != null) { count = (Integer) object; } sortList.add(new ApplyKey(key, count)); } sortList.sort(Comparator.comparing(ApplyKey::getCount).reversed()); for (ApplyKey applyKey : sortList) { String key = applyKey.getKey(); TrafficControlDataModel dataModel = (TrafficControlDataModel) redisUtil.get(key); redisUtil.del(key); boolean apply = trafficControlThread.processApply(dataModel); String applyCountKey = RedisKeyType.TRAFFIC_CONTROL_SHUTTLE_APPLY_COUNT.key + dataModel.getShuttleNo(); if (apply) { redisUtil.del(applyCountKey); }else { Object object = redisUtil.get(applyCountKey); if (object == null) { redisUtil.set(applyCountKey, 0, 60 * 60); }else { Integer count = (Integer) object; redisUtil.set(applyCountKey, count + 1, 60 * 60); } } } } @Scheduled(cron = "0/3 * * * * ? ") public void processReport() { TrafficControlThread trafficControlThread = (TrafficControlThread) SlaveConnection.get(SlaveType.TrafficControl, 1); if (trafficControlThread == null) { return; } Set<String> keys = redisUtil.searchKeys(RedisKeyType.TRAFFIC_CONTROL_REPORT_LIST.key); for (String key : keys) { OperateTrafficControlParam param = (OperateTrafficControlParam) redisUtil.get(key); redisUtil.del(key); boolean apply = trafficControlThread.operateTrafficControl(param); } } class ApplyKey{ @Getter String key; @Getter Integer count; public ApplyKey(String key, Integer count) { this.key = key; this.count = count; } } } src/main/java/com/zy/core/thread/TrafficControlThread.java
@@ -4,11 +4,16 @@ import com.zy.common.model.NavigateNode; import com.zy.core.ThreadHandler; import com.zy.core.model.TrafficControlDataModel; import com.zy.core.model.param.OperateTrafficControlParam; import java.util.List; public interface TrafficControlThread extends ThreadHandler { boolean processApply(TrafficControlDataModel applyData); boolean operateTrafficControl(OperateTrafficControlParam param); boolean applyTrafficControl(List<NavigateNode> totalNodeList, List<NavigateNode> nodeList, Integer shuttleNo, Integer taskNo); boolean trafficReport(List<NavigateNode> nodeList, Integer shuttleNo, Integer taskNo); src/main/java/com/zy/core/thread/impl/NyShuttleThread.java
@@ -89,35 +89,35 @@ }); readThread.start(); //设备执行 Thread executeThread = new Thread(() -> { while (true) { try { if (shuttleAction == null) { try { shuttleAction = SpringUtils.getBean(ShuttleAction.class); }catch (Exception e){ } continue; } Object object = redisUtil.get(RedisKeyType.SHUTTLE_FLAG.key + deviceConfig.getDeviceNo()); if (object == null) { continue; } Integer taskNo = Integer.valueOf(String.valueOf(object)); if (taskNo != 0) { //存在任务需要执行 boolean result = shuttleAction.executeWork(deviceConfig.getDeviceNo(), taskNo); } Thread.sleep(100); } catch (Exception e) { e.printStackTrace(); } } }); executeThread.start(); // //设备执行 // Thread executeThread = new Thread(() -> { // while (true) { // try { // if (shuttleAction == null) { // try { // shuttleAction = SpringUtils.getBean(ShuttleAction.class); // }catch (Exception e){ // } // continue; // } // // Object object = redisUtil.get(RedisKeyType.SHUTTLE_FLAG.key + deviceConfig.getDeviceNo()); // if (object == null) { // continue; // } // // Integer taskNo = Integer.valueOf(String.valueOf(object)); // if (taskNo != 0) { // //存在任务需要执行 // boolean result = shuttleAction.executeWork(deviceConfig.getDeviceNo(), taskNo); // } // Thread.sleep(100); // } catch (Exception e) { // e.printStackTrace(); // } // } // }); // executeThread.start(); } private void listenMessageFromRedis() { src/main/java/com/zy/core/thread/impl/TrafficControlImplThread.java
@@ -1,13 +1,8 @@ package com.zy.core.thread.impl; import com.alibaba.fastjson.JSON; import com.core.common.SpringUtils; import com.fasterxml.jackson.databind.ObjectMapper; import com.zy.asrs.utils.Utils; import com.zy.common.model.NavigateNode; import com.zy.common.model.enums.NavigationMapType; import com.zy.common.utils.NavigatePositionConvert; import com.zy.common.utils.NavigateUtils; import com.zy.common.utils.RedisUtil; import com.zy.common.utils.ShuttleOperaUtils; import com.zy.core.News; @@ -15,16 +10,14 @@ import com.zy.core.enums.RedisKeyType; import com.zy.core.enums.SlaveType; import com.zy.core.model.TrafficControlDataModel; import com.zy.core.model.command.ShuttleAssignCommand; import com.zy.core.model.command.ShuttleRedisCommand; import com.zy.core.model.param.OperateTrafficControlParam; import com.zy.core.model.protocol.ShuttleProtocol; import com.zy.core.thread.ShuttleThread; import com.zy.core.thread.TrafficControlThread; import com.zy.core.utils.TrafficControlUtils; import org.springframework.scheduling.annotation.Async; import java.io.IOException; import java.util.*; import java.util.function.Function; import java.util.stream.Collectors; public class TrafficControlImplThread implements TrafficControlThread { @@ -36,6 +29,7 @@ private HashMap<Integer,Long> applyRecordsMap = new HashMap<>(); private HashMap<String, List<NavigateNode>> taskNodesMap = new HashMap<>(); private List<TrafficControlDataModel> trafficControlDataList = new ArrayList<>(); private List<TrafficControlDataModel> trafficControlDataListRead = new ArrayList<>(); public TrafficControlImplThread(RedisUtil redisUtil) { this.redisUtil = redisUtil; @@ -47,17 +41,22 @@ Object object = redisUtil.get(RedisKeyType.TRAFFIC_CONTROL_MAP.key); if(object != null) { trafficControlDataList = (List<TrafficControlDataModel>) object; trafficControlDataListRead = trafficControlDataList.stream() .map(model -> new TrafficControlDataModel( model.getShuttleNo(), model.getTaskNo(), new ArrayList<>(model.getNodeList()), new ArrayList<>(model.getTotalNodeList()) )) .collect(Collectors.toList()); } while (true) { try { if (applyList.isEmpty()) { continue; } TrafficControlDataModel dataModel = applyList.get(0); processApply(dataModel); applyList.remove(0); List<TrafficControlDataModel> allTrafficControl = getAllTrafficControl(); //更新交管信息 redisUtil.set(RedisKeyType.TRAFFIC_CONTROL_MAP.key, allTrafficControl); Thread.sleep(200); }catch (Exception e){ e.printStackTrace(); } @@ -65,6 +64,7 @@ } @Override public synchronized boolean processApply(TrafficControlDataModel applyData) { ShuttleOperaUtils shuttleOperaUtils = SpringUtils.getBean(ShuttleOperaUtils.class); if (shuttleOperaUtils == null) { @@ -79,13 +79,12 @@ return false; } List<TrafficControlDataModel> allTrafficControlList = getAllTrafficControl(); Integer shuttleNo = applyData.getShuttleNo(); Integer taskNo = applyData.getTaskNo(); List<NavigateNode> nodeList = applyData.getNodeList(); List<NavigateNode> totalNodeList = applyData.getTotalNodeList(); //更新交管信息 redisUtil.set(RedisKeyType.TRAFFIC_CONTROL_MAP.key, trafficControlDataList); NavigateNode startNode = totalNodeList.get(0); List<int[]> shuttlePoints = Utils.getShuttlePoints(shuttleNo, startNode.getZ()); @@ -103,8 +102,8 @@ } //检测车子是否存在管制 for (int i = 0; i < trafficControlDataList.size(); i++) { TrafficControlDataModel controlDataModel = trafficControlDataList.get(i); for (int i = 0; i < allTrafficControlList.size(); i++) { TrafficControlDataModel controlDataModel = allTrafficControlList.get(i); if(shuttleNo.equals(controlDataModel.getShuttleNo())) { //存在管制 if(!controlDataModel.getTaskNo().equals(taskNo)) { @@ -178,7 +177,7 @@ } //检测节点是否被使用 for (TrafficControlDataModel controlDataModel : trafficControlDataList) { for (TrafficControlDataModel controlDataModel : allTrafficControlList) { List<NavigateNode> list = controlDataModel.getTotalNodeList(); for (int i = 0; i < list.size(); i++) { NavigateNode node = list.get(i); @@ -194,7 +193,10 @@ } //交管接收 trafficControlDataList.add(applyData); OperateTrafficControlParam param = new OperateTrafficControlParam(); param.setDataModel(applyData); param.setOperaType("add"); operateTrafficControl(param); applyRecordsMap.remove(shuttleNo); News.info("receipt traffic {},{}", shuttleNo, taskNo); @@ -202,55 +204,34 @@ } @Override public synchronized boolean applyTrafficControl(List<NavigateNode> totalNodeList, List<NavigateNode> nodeList, Integer shuttleNo, Integer taskNo) { boolean add = true; for (TrafficControlDataModel controlDataModel : applyList) { if(controlDataModel.getShuttleNo().equals(shuttleNo)) { add = false; break; } } if (add) { TrafficControlDataModel model = new TrafficControlDataModel(); model.setShuttleNo(shuttleNo); model.setTaskNo(taskNo); model.setNodeList(nodeList); model.setTotalNodeList(totalNodeList); applyList.add(model); }else { public boolean applyTrafficControl(List<NavigateNode> totalNodeList, List<NavigateNode> nodeList, Integer shuttleNo, Integer taskNo) { Set<String> keys = redisUtil.searchKeys(RedisKeyType.TRAFFIC_CONTROL_APPLY.key + shuttleNo + "_"); if (!keys.isEmpty()) { return false; } TrafficControlDataModel model = new TrafficControlDataModel(); model.setShuttleNo(shuttleNo); model.setTaskNo(taskNo); model.setNodeList(nodeList); model.setTotalNodeList(totalNodeList); redisUtil.set(RedisKeyType.TRAFFIC_CONTROL_APPLY.key + shuttleNo + "_" + System.currentTimeMillis(), model); return true; } @Override public synchronized boolean trafficReport(List<NavigateNode> nodeList, Integer shuttleNo, Integer taskNo) { public boolean trafficReport(List<NavigateNode> nodeList, Integer shuttleNo, Integer taskNo) { //检测车子是否存在管制 for (int i = 0; i < trafficControlDataList.size(); i++) { TrafficControlDataModel controlDataModel = trafficControlDataList.get(i); List<TrafficControlDataModel> allTrafficControlList = getAllTrafficControl(); for (int i = 0; i < allTrafficControlList.size(); i++) { TrafficControlDataModel controlDataModel = allTrafficControlList.get(i); if(shuttleNo.equals(controlDataModel.getShuttleNo())) { if(controlDataModel.getTaskNo().equals(taskNo)) { List<NavigateNode> newTotalNodeList = new ArrayList<>(); List<NavigateNode> totalNodeList = controlDataModel.getTotalNodeList(); List<String> reportList = new ArrayList<>(); for (NavigateNode node : nodeList) { reportList.add(Utils.getLocNo(node.getX(), node.getY(), node.getZ())); } for (NavigateNode node : totalNodeList) { String locNo = Utils.getLocNo(node.getX(), node.getY(), node.getZ()); if(reportList.contains(locNo)) { continue; } newTotalNodeList.add(node); } controlDataModel.setTotalNodeList(newTotalNodeList); trafficControlDataList.set(i, controlDataModel); shuttleReportErrorMap.remove(shuttleNo); OperateTrafficControlParam param = new OperateTrafficControlParam(); param.setDataModel(controlDataModel); param.setOperaType("report"); param.setReportNodeList(nodeList); redisUtil.set(RedisKeyType.TRAFFIC_CONTROL_REPORT_LIST.key + shuttleNo + "_" + System.currentTimeMillis(), param); return true; } } @@ -259,7 +240,7 @@ } @Override public boolean trafficReportError(Integer shuttleNo, Integer taskNo) { public synchronized boolean trafficReportError(Integer shuttleNo, Integer taskNo) { ShuttleThread shuttleThread = (ShuttleThread) SlaveConnection.get(SlaveType.Shuttle, shuttleNo); if (shuttleThread == null) { return false; @@ -279,37 +260,38 @@ @Override public synchronized boolean cancelTrafficControl(Integer shuttleNo, Integer taskNo) { //检测车子是否存在管制 for (int i = 0; i < trafficControlDataList.size(); i++) { TrafficControlDataModel controlDataModel = trafficControlDataList.get(i); if(shuttleNo.equals(controlDataModel.getShuttleNo())) { if(controlDataModel.getTaskNo().equals(taskNo)) { trafficControlDataList.remove(i);//取消管制 return true; } } TrafficControlDataModel dataModel = queryTrafficControl(shuttleNo, taskNo); if (dataModel == null) { return false; } return false; OperateTrafficControlParam param = new OperateTrafficControlParam(); param.setDataModel(dataModel); param.setOperaType("cancel"); param.setForceCancel(false); return operateTrafficControl(param); } @Override public boolean forceCancelTrafficControl(Integer shuttleNo) { //检测车子是否存在管制 for (int i = 0; i < trafficControlDataList.size(); i++) { TrafficControlDataModel controlDataModel = trafficControlDataList.get(i); if(shuttleNo.equals(controlDataModel.getShuttleNo())) { trafficControlDataList.remove(i);//取消管制 return true; } public synchronized boolean forceCancelTrafficControl(Integer shuttleNo) { TrafficControlDataModel dataModel = queryTrafficControl(shuttleNo); if (dataModel == null) { return false; } return false; OperateTrafficControlParam param = new OperateTrafficControlParam(); param.setDataModel(dataModel); param.setOperaType("cancel"); param.setForceCancel(true); return operateTrafficControl(param); } @Override public TrafficControlDataModel queryTrafficControl(Integer shuttleNo, Integer taskNo) { //检测车子是否存在管制 for (int i = 0; i < trafficControlDataList.size(); i++) { TrafficControlDataModel controlDataModel = trafficControlDataList.get(i); List<TrafficControlDataModel> allTrafficControlList = getAllTrafficControl(); for (int i = 0; i < allTrafficControlList.size(); i++) { TrafficControlDataModel controlDataModel = allTrafficControlList.get(i); if(shuttleNo.equals(controlDataModel.getShuttleNo())) { if(controlDataModel.getTaskNo().equals(taskNo)) { return controlDataModel; @@ -322,8 +304,9 @@ @Override public TrafficControlDataModel queryTrafficControl(Integer shuttleNo) { //检测车子是否存在管制 for (int i = 0; i < trafficControlDataList.size(); i++) { TrafficControlDataModel controlDataModel = trafficControlDataList.get(i); List<TrafficControlDataModel> allTrafficControlList = getAllTrafficControl(); for (int i = 0; i < allTrafficControlList.size(); i++) { TrafficControlDataModel controlDataModel = allTrafficControlList.get(i); if(shuttleNo.equals(controlDataModel.getShuttleNo())) { return controlDataModel; } @@ -333,7 +316,110 @@ @Override public List<TrafficControlDataModel> getAllTrafficControl() { return trafficControlDataList; return trafficControlDataListRead; } @Override public synchronized boolean operateTrafficControl(OperateTrafficControlParam param) { long startTime = System.currentTimeMillis(); String operaType = param.getOperaType(); News.info("Operate Traffic Control is Start " + operaType); boolean result = false; if (operaType.equals("add")) { result = addTrafficControlDataList(param); } else if (operaType.equals("cancel")) { result = removeTrafficControlDataList(param); } else if (operaType.equals("report")) { result = reportTrafficControlDataList(param); } this.trafficControlDataListRead = trafficControlDataList.stream() .map(model -> new TrafficControlDataModel( model.getShuttleNo(), model.getTaskNo(), new ArrayList<>(model.getNodeList()), new ArrayList<>(model.getTotalNodeList()) )) .collect(Collectors.toList()); News.info("Operate Traffic Control is end " + (System.currentTimeMillis() - startTime) + "ms"); return result; } public synchronized boolean addTrafficControlDataList(OperateTrafficControlParam param) { TrafficControlDataModel dataModel = param.getDataModel(); trafficControlDataList.add(dataModel); return true; } public synchronized boolean removeTrafficControlDataList(OperateTrafficControlParam param) { //检测车子是否存在管制 TrafficControlDataModel dataModel = param.getDataModel(); Boolean forceCancel = param.getForceCancel(); Integer shuttleNo = dataModel.getShuttleNo(); Integer taskNo = dataModel.getTaskNo(); int idx = -1; for (int i = 0; i < trafficControlDataList.size(); i++) { TrafficControlDataModel controlDataModel = trafficControlDataList.get(i); if(shuttleNo.equals(controlDataModel.getShuttleNo())) { if (forceCancel) { idx = i; break; }else { if(controlDataModel.getTaskNo().equals(taskNo)) { idx = i; break; } } } } if(idx == -1) { return false; } trafficControlDataList.remove(idx);//取消管制 return true; } public synchronized boolean reportTrafficControlDataList(OperateTrafficControlParam param) { //检测车子是否存在管制 TrafficControlDataModel dataModel = param.getDataModel(); List<NavigateNode> reportNodeList = param.getReportNodeList(); Integer shuttleNo = dataModel.getShuttleNo(); Integer taskNo = dataModel.getTaskNo(); for (int i = 0; i < trafficControlDataList.size(); i++) { TrafficControlDataModel controlDataModel = trafficControlDataList.get(i); if(shuttleNo.equals(controlDataModel.getShuttleNo())) { if(controlDataModel.getTaskNo().equals(taskNo)) { List<NavigateNode> newTotalNodeList = new ArrayList<>(); List<NavigateNode> totalNodeList = controlDataModel.getTotalNodeList(); List<String> reportList = new ArrayList<>(); for (NavigateNode node : reportNodeList) { reportList.add(Utils.getLocNo(node.getX(), node.getY(), node.getZ())); } for (NavigateNode node : totalNodeList) { String locNo = Utils.getLocNo(node.getX(), node.getY(), node.getZ()); if(reportList.contains(locNo)) { continue; } newTotalNodeList.add(node); } controlDataModel.setTotalNodeList(newTotalNodeList); trafficControlDataList.set(i, controlDataModel); shuttleReportErrorMap.remove(shuttleNo); return true; } } } return false; } @Override src/main/resources/application.yml
@@ -50,6 +50,10 @@ # 读取数据后自动删除 destroyAfterReading: true deviceExecuteConfig: # 每个线程管控设备执行数量 threadControlCount: 10 ## 下位机配置 #wcs-slave: # # 四向穿梭车1 src/main/webapp/views/shuttleNew.html
@@ -183,12 +183,18 @@ <el-input @change="changeControlShuttleNo" v-model="controlData.shuttleNo" style="width: 150px;" placeholder="车辆编号"></el-input> </div> <div> <el-input @change="changeControlShuttleNo" v-model="controlData.taskNo" style="width: 150px;" placeholder="工作号"></el-input> </div> <div> <el-input v-model="controlData.sourceLocNo" style="width: 200px;" placeholder="源库位"></el-input> </div> <div> <el-input v-model="controlData.targetLocNo" style="width: 200px;" placeholder="目标库位"></el-input> </div> <div> <button class="btn bg-slate-600 hover:bg-slate-500" @click="shuttleOperator('writeTaskNo')"> <i class="fas fa-credit-card-alt mr-1"></i>写入工作号 </button> <button class="btn bg-slate-600 hover:bg-slate-500" @click="shuttleOperator('transport')"> <i class="fas fa-truck mr-1"></i>搬运货物 </button> @@ -224,6 +230,9 @@ </button> <button class="btn bg-slate-600 hover:bg-slate-500" @click="shuttleOperator('demoOff')"> <i class="fas fa-hourglass-empty mr-1"></i>演示-关 </button> <button class="btn bg-slate-600 hover:bg-slate-500" @click="shuttleOperator('clearPath')"> <i class="fas fa-anchor mr-1"></i>清除路径 </button> </div> </div> @@ -393,6 +402,7 @@ deviceStatusCountMap: {}, controlData: { shuttleNo: "", taskNo: "", sourceLocNo: "", targetLocNo: "" }, @@ -557,6 +567,34 @@ requestParam.shuttleTaskMode = 12; }else if (type == 'demoOff') { requestParam.shuttleTaskMode = 13; }else if (type == 'clearPath') { requestParam.shuttleTaskMode = 17; }else if (type == 'writeTaskNo') { requestParam.workNo = this.controlData.taskNo; requestParam.pakMk = null; $.ajax({ url: baseUrl + "/shuttle/detl/update", headers: {'token': localStorage.getItem('token')}, method: 'POST', data: requestParam, success: function (res) { if (res.code === 200) { that.$message({ message: res.msg, type: 'success' }); } else if (res.code === 403) { window.location.href = baseUrl + "/login"; } else { that.$message({ message: res.msg, type: 'warning' }); } } }); return; } $.ajax({ @@ -573,7 +611,7 @@ } else if (res.code === 403) { window.location.href = baseUrl + "/login"; } else { this.$message({ that.$message({ message: res.msg, type: 'warning' }); src/main/webapp/views/trafficControl.html
New file @@ -0,0 +1,208 @@ <!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>交通管制监控中心</title> <link rel="stylesheet" href="../static/vue/element/element.css"> <link rel="stylesheet" href="../static/css/shuttle_page.min.css"> <script src="../static/js/shuttle_page.js"></script> <script type="text/javascript" src="../static/js/jquery/jquery-3.3.1.min.js"></script> <script type="text/javascript" src="../static/js/common.js"></script> <script type="text/javascript" src="../static/vue/js/vue.min.js"></script> <script type="text/javascript" src="../static/vue/element/element.js"></script> <style> body { font-family: 'Noto Sans SC', sans-serif; background-color: #0f172a; color: #e2e8f0; } .card { background-color: #1e293b; border-radius: 0.75rem; box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1); transition: all 0.3s ease; } /*.card:hover {*/ /* transform: translateY(-2px);*/ /* box-shadow: 0 10px 15px rgba(0, 0, 0, 0.2);*/ /*}*/ .btn { background-color: #3b82f6; color: white; border-radius: 0.5rem; padding: 0.5rem 1rem; transition: all 0.3s ease; } .btn:hover { background-color: #2563eb; transform: translateY(-1px); } .status-active { color: #4ade80; } .status-inactive { color: #f87171; } .progress-bar { height: 0.75rem; border-radius: 0.375rem; background-color: #334155; } .progress-fill { height: 100%; border-radius: 0.375rem; background-color: #4ade80; transition: width 0.5s ease; } .table-striped tbody tr:nth-child(odd) { background-color: #1e293b; } .table-striped tbody tr:nth-child(even) { background-color: #1a2537; } </style> </head> <body class="min-h-screen"> <div id="app"> <div class="container mx-auto px-4 py-8"> <!-- 顶部标题和状态栏 --> <div class="flex flex-col md:flex-row justify-between items-center mb-8"> <h1 class="text-3xl font-bold text-blue-400 mb-4 md:mb-0"> <i class="fas fa-robot mr-2"></i>交通管制监控中心 </h1> </div> <!-- 操作控制区域 --> <div class="card p-6 mb-8"> <h2 class="text-xl font-semibold text-blue-300 mb-4"> <i class="fas fa-sliders-h mr-2"></i>信息 </h2> <div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-2 gap-2"> <div v-for="(item) in controlList" class="bg-slate-700 p-4 rounded-lg"> <div class="gap-2"> <div class="p-2"> <button class="btn bg-slate-600 hover:bg-slate-500" @click="cancelTraffic(item)"> <i class="fas fa-home mr-1"></i>申请取消 </button> </div> <div class="p-2"> 车辆编号:{{ item.shuttleNo }} </div> <div class="p-2"> 任务号:{{ item.taskNo }} - {{ item.taskExist }} </div> <div class="p-2"> 当前行驶节点:{{ item.nodeList }} </div> <div class="p-2"> 总节点:{{ item.totalNodeList }} </div> </div> </div> </div> </div> </div> </div> </body> <script> var app = new Vue({ el: '#app', data: { ws: null, controlList: [] }, created() { this.init() }, watch: { }, methods: { init() { this.consoleInterval = setInterval(() => { this.getTrafficControlInfos() }, 1000) }, getTrafficControlInfos() { let that = this; $.ajax({ url: baseUrl + "/trafficControl/getTrafficControlInfos", headers: {'token': localStorage.getItem('token')}, method: 'GET', data: {}, success: function (res) { if (res.code === 200) { let list = [] res.data.forEach((item) => { let nodeList = [] item.nodeList.forEach((nodeItem) => { let tmp = { x: nodeItem.x, y: nodeItem.y, z: nodeItem.z } nodeList.push(tmp) }) let totalNodeList = [] item.totalNodeList.forEach((nodeItem) => { let tmp = { x: nodeItem.x, y: nodeItem.y, z: nodeItem.z } totalNodeList.push(tmp) }) item.nodeList = nodeList; item.totalNodeList = totalNodeList; list.push(item) }) that.controlList = list; } else if (res.code === 403) { window.location.href = baseUrl + "/login"; } else { that.$message({ message: res.msg, type: 'warning' }); } } }); }, cancelTraffic(item) { let that = this; $.ajax({ url: baseUrl + "/trafficControl/cancelTraffic", headers: {'token': localStorage.getItem('token')}, method: 'POST', data: { shuttleNo: item.shuttleNo, taskNo: item.taskNo }, success: function (res) { if (res.code === 200) { that.$message({ message: res.msg, type: 'success' }); } else if (res.code === 403) { window.location.href = baseUrl + "/login"; } else { that.$message({ message: res.msg, type: 'warning' }); } } }); } } }) </script> </html>