src/main/java/com/zy/asrs/controller/BasMapController.java
@@ -130,6 +130,16 @@ return R.ok(); } @GetMapping("/basMap/lev/{lev}/auth") @ManagerAuth public R getByLev(@PathVariable("lev") Integer lev) { BasMap basMap = basMapService.selectOne(new EntityWrapper<BasMap>().eq("lev", lev)); if (basMap == null){ return R.error("地图不存在"); } return R.ok().add(basMap.getData()); } @Autowired private MapExcelUtils mapExcelUtils; @@ -165,7 +175,6 @@ }else if (nodeType.equals("RGB(0,112,192)")) { //输送线 nodeData.put("type", "devp"); nodeData.put("value", (int) Double.parseDouble(map.get("value").toString())); }else if (nodeType.equals("RGB(0,176,240)")) { //RGV nodeData.put("type", "rgv"); @@ -188,8 +197,17 @@ } } return R.ok().add(JSON.toJSONString(dataList)); BasMap basMap = basMapService.selectOne(new EntityWrapper<BasMap>().eq("lev", 1)); if (basMap == null){ basMap = new BasMap(); } basMap.setLev(1); basMap.setData(JSON.toJSONString(dataList)); basMap.setOriginData(JSON.toJSONString(dataList)); basMap.setCreateTime(new Date()); basMap.setUpdateTime(new Date()); basMapService.insertOrUpdate(basMap); return R.ok(); } } src/main/java/com/zy/asrs/controller/ConsoleController.java
@@ -1,15 +1,15 @@ package com.zy.asrs.controller; import com.alibaba.fastjson.JSON; import com.baomidou.mybatisplus.mapper.EntityWrapper; import com.core.annotations.ManagerAuth; import com.core.common.Cools; import com.core.common.R; import com.core.exception.CoolException; import com.zy.asrs.domain.enums.CrnStatusType; import com.zy.asrs.domain.enums.StationStatusType; import com.zy.asrs.domain.param.SystemSwitchParam; import com.zy.asrs.domain.vo.CrnDetailVo; import com.zy.asrs.domain.vo.CrnLatestDataVo; import com.zy.asrs.domain.vo.StationLatestDataVo; import com.zy.asrs.entity.BasCrnpErr; import com.zy.asrs.entity.DeviceConfig; import com.zy.asrs.entity.WrkMast; @@ -17,15 +17,15 @@ import com.zy.asrs.service.DeviceConfigService; import com.zy.asrs.service.WrkMastService; import com.zy.common.CodeRes; import com.zy.core.Slave; import com.zy.core.ThreadHandler; import com.zy.core.cache.SlaveConnection; import com.zy.core.enums.CrnModeType; import com.zy.core.enums.SlaveType; import com.zy.core.model.protocol.CrnProtocol; import com.zy.core.model.protocol.StationProtocol; import com.zy.core.properties.SystemProperties; import com.zy.core.thread.CrnThread; import com.zy.core.thread.impl.ZySiemensCrnThread; import com.zy.core.thread.StationThread; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.*; @@ -50,54 +50,73 @@ @PostMapping("/system/running/status") @ManagerAuth(memo = "系统运行状态") public R systemRunningStatus(){ public R systemRunningStatus() { return R.ok().add(Cools.add("status", SystemProperties.WCS_RUNNING_STATUS.get())); } @PostMapping("/system/switch") @ManagerAuth(memo = "系统运行开关操作") public R systemSwitch(SystemSwitchParam param) throws InterruptedException { if (Cools.isEmpty(param.getOperatorType())){ if (Cools.isEmpty(param.getOperatorType())) { return R.error(); } if (param.getOperatorType() == 0) { if (Cools.isEmpty(param.getPassword())){ if (Cools.isEmpty(param.getPassword())) { return R.error("请输入口令"); } if (!param.getPassword().equals(SystemProperties.WCS_PASSWORD)){ if (!param.getPassword().equals(SystemProperties.WCS_PASSWORD)) { return R.error("口令错误"); } } Thread.sleep(200L); SystemProperties.WCS_RUNNING_STATUS.set(param.getOperatorType()==1?Boolean.TRUE:Boolean.FALSE); SystemProperties.WCS_RUNNING_STATUS.set(param.getOperatorType() == 1 ? Boolean.TRUE : Boolean.FALSE); return R.ok().add(Cools.add("status", SystemProperties.WCS_RUNNING_STATUS.get())); } // @PostMapping("/latest/data/site") // @ManagerAuth(memo = "站点实时数据") // public R siteLatestData(){ // List<SiteLatestDataVo> vos = new ArrayList<>(); // Map<Integer, StaProtocol> stations = new HashMap<>(); // for (DevpSlave devp : slaveProperties.getDevp()) { // DevpThread devpThread = (DevpThread) SlaveConnection.get(SlaveType.Devp, devp.getId()); // if (null != devpThread) { // stations.putAll(devpThread.getStation()); // } // } // for (Map.Entry<Integer, StaProtocol> entry : stations.entrySet()) { // SiteLatestDataVo vo = new SiteLatestDataVo(); // StaProtocol staProtocol = entry.getValue(); // vo.setSiteId(String.valueOf(entry.getKey())); // 站点编号 // vo.setWorkNo(staProtocol.getWorkNo()); // 工作号 // vo.setSiteStatus(SiteStatusType.process(staProtocol)); // 状态 // vos.add(vo); // } // return R.ok().add(vos); // } @PostMapping("/latest/data/station") @ManagerAuth(memo = "站点实时数据") public R stationLatestData() { List<StationLatestDataVo> vos = new ArrayList<>(); List<DeviceConfig> devpList = deviceConfigService.selectList(new EntityWrapper<DeviceConfig>() .eq("device_type", String.valueOf(SlaveType.Devp))); for (DeviceConfig deviceConfig : devpList) { StationThread stationThread = (StationThread) SlaveConnection.get(SlaveType.Devp, deviceConfig.getDeviceNo()); if (stationThread == null) { continue; } List<StationProtocol> statusList = stationThread.getStatus(); if (statusList == null || statusList.isEmpty()) { continue; } for (StationProtocol stationProtocol : statusList) { StationLatestDataVo vo = new StationLatestDataVo(); vo.setStationId(stationProtocol.getStationId()); // 站点编号 vo.setTaskNo(stationProtocol.getTaskNo()); // 任务号 vo.setTargetStaNo(stationProtocol.getTargetStaNo()); // 目标站点 vo.setAutoing(stationProtocol.isAutoing()); // 是否自动 vo.setLoading(stationProtocol.isLoading()); // 是否有物 vo.setInEnable(stationProtocol.isInEnable()); // 是否可入 vo.setOutEnable(stationProtocol.isOutEnable()); // 是否可出 vo.setEmptyMk(stationProtocol.isEmptyMk()); // 是否空板 vo.setFullPlt(stationProtocol.isFullPlt()); // 是否满板 vo.setPalletHeight(stationProtocol.getPalletHeight()); // 托盘高度 vo.setError(stationProtocol.getError()); // 错误码 vo.setBarcode(stationProtocol.getBarcode()); // 条码 String stationStatus = StationStatusType.process(stationProtocol).toString().toLowerCase().replaceAll("_", "-"); vo.setStationStatus(stationStatus); vos.add(vo); } } return R.ok().add(vos); } @PostMapping("/latest/data/crn") @ManagerAuth(memo = "堆垛机实时数据") public R crnLatestData(){ public R crnLatestData() { List<CrnLatestDataVo> vos = new ArrayList<>(); List<DeviceConfig> crnList = deviceConfigService.selectList(new EntityWrapper<DeviceConfig>() @@ -114,25 +133,27 @@ continue; } CrnLatestDataVo vo = new CrnLatestDataVo(); vo.setCrnId(crnProtocol.getCrnNo()); // 堆垛机编号 vo.setCrnId(crnProtocol.getCrnNo()); // 堆垛机编号 vo.setOffset((double) new Random().nextInt(560)); // 堆垛机偏移量 vo.setBay(crnProtocol.getBay()); // 当前列 vo.setOffset((double) new Random().nextInt(560)); // 堆垛机偏移量 vo.setBay(crnProtocol.getBay()); // 当前列 /** * 堆垛机状态判断 */ if (crnProtocol.getAlarm() > 0) { vo.setCrnStatus(CrnStatusType.MACHINE_ERROR); } else { if (crnProtocol.getTaskNo()>0) { if (crnProtocol.getTaskNo() > 0) { WrkMast wrkMast = wrkMastService.selectById(crnProtocol.getTaskNo()); if (wrkMast != null) { vo.setCrnStatus(CrnStatusType.process(wrkMast.getIoType())); } else { vo.setCrnStatus(crnProtocol.modeType.equals(CrnModeType.AUTO)? CrnStatusType.MACHINE_AUTO: CrnStatusType.MACHINE_UN_AUTO); vo.setCrnStatus(crnProtocol.modeType.equals(CrnModeType.AUTO) ? CrnStatusType.MACHINE_AUTO : CrnStatusType.MACHINE_UN_AUTO); } } else { vo.setCrnStatus(crnProtocol.modeType.equals(CrnModeType.AUTO)? CrnStatusType.MACHINE_AUTO: CrnStatusType.MACHINE_UN_AUTO); vo.setCrnStatus(crnProtocol.modeType.equals(CrnModeType.AUTO) ? CrnStatusType.MACHINE_AUTO : CrnStatusType.MACHINE_UN_AUTO); } } vos.add(vo); @@ -140,61 +161,62 @@ return R.ok().add(vos); } // @PostMapping("/latest/data/rgv") // @ManagerAuth(memo = "RGV实时数据") // public R rgvLatestData(){ // List<RgvLatestDataVo> vos = new ArrayList<>(); // for (RgvSlave rgvSlave : slaveProperties.getRgv()) { // // 获取堆垛机信息 // RgvThread rgvThread = (RgvThread) SlaveConnection.get(SlaveType.Rgv, rgvSlave.getId()); // if (rgvThread == null) { // continue; // } // RgvProtocol rgvProtocol = rgvThread.getRgvProtocol(); // if (rgvProtocol == null) { // continue; // } // RgvLatestDataVo vo = new RgvLatestDataVo(); // vo.setRgvId(rgvProtocol.getRgvNo()); // RGV编号 // vo.setTrackSiteNo(String.valueOf(rgvProtocol.getRgvPos())); // vo.setRgvStatus(rgvProtocol.getStatusType()); // vos.add(vo); // // } // Object object = redisUtil.get("rgvLatestData"); // List<Object> siteLatestDataVos = JSON.parseArray(object.toString()); // return R.ok().add(siteLatestDataVos); // } // @PostMapping("/latest/data/rgv") // @ManagerAuth(memo = "RGV实时数据") // public R rgvLatestData(){ // List<RgvLatestDataVo> vos = new ArrayList<>(); // for (RgvSlave rgvSlave : slaveProperties.getRgv()) { // // 获取堆垛机信息 // RgvThread rgvThread = (RgvThread) SlaveConnection.get(SlaveType.Rgv, // rgvSlave.getId()); // if (rgvThread == null) { // continue; // } // RgvProtocol rgvProtocol = rgvThread.getRgvProtocol(); // if (rgvProtocol == null) { // continue; // } // RgvLatestDataVo vo = new RgvLatestDataVo(); // vo.setRgvId(rgvProtocol.getRgvNo()); // RGV编号 // vo.setTrackSiteNo(String.valueOf(rgvProtocol.getRgvPos())); // vo.setRgvStatus(rgvProtocol.getStatusType()); // vos.add(vo); // // } // Object object = redisUtil.get("rgvLatestData"); // List<Object> siteLatestDataVos = JSON.parseArray(object.toString()); // return R.ok().add(siteLatestDataVos); // } // @PostMapping("/latest/data/barcode") // @ManagerAuth(memo = "条码扫描仪实时数据") // public R barcodeLatestData(){ // List<BarcodeDataVo> list = new ArrayList<>(); // for (Slave barcode : slaveProperties.getBarcode()) { // BarcodeThread barcodeThread = (BarcodeThread) SlaveConnection.get(SlaveType.Barcode, barcode.getId()); // if (null == barcodeThread) { // continue; // } // BarcodeDataVo vo = new BarcodeDataVo(); // vo.setBarcodeId(barcode.getId()); // vo.setCodeValue(barcodeThread.getBarcode()); // list.add(vo); // } // return R.ok().add(list); // } // @PostMapping("/latest/data/barcode") // @ManagerAuth(memo = "条码扫描仪实时数据") // public R barcodeLatestData(){ // List<BarcodeDataVo> list = new ArrayList<>(); // for (Slave barcode : slaveProperties.getBarcode()) { // BarcodeThread barcodeThread = (BarcodeThread) // SlaveConnection.get(SlaveType.Barcode, barcode.getId()); // if (null == barcodeThread) { // continue; // } // BarcodeDataVo vo = new BarcodeDataVo(); // vo.setBarcodeId(barcode.getId()); // vo.setCodeValue(barcodeThread.getBarcode()); // list.add(vo); // } // return R.ok().add(list); // } @PostMapping("/crn/detail") @ManagerAuth(memo = "堆垛机设备数据详情") public R crnDetail(@RequestParam Integer crnNo){ if (Cools.isEmpty(crnNo)){ public R crnDetail(@RequestParam Integer crnNo) { if (Cools.isEmpty(crnNo)) { return R.parse(CodeRes.EMPTY); } CrnDetailVo vo = new CrnDetailVo(); DeviceConfig deviceConfig = deviceConfigService.selectOne(new EntityWrapper<DeviceConfig>() .eq("device_type", String.valueOf(SlaveType.Crn)) .eq("device_no", crnNo) ); .eq("device_no", crnNo)); if (deviceConfig == null) { return R.error("设备不存在"); @@ -216,12 +238,12 @@ if (wrkMast != null) { vo.setSourceStaNo(String.valueOf(wrkMast.getSourceStaNo())); vo.setStaNo(String.valueOf(wrkMast.getStaNo())); vo.setWrkSts(wrkMast.getWrkSts$()); // 工作状态 vo.setIoType(wrkMast.getIoType$()); // 入出库类型 vo.setWrkSts(wrkMast.getWrkSts$()); // 工作状态 vo.setIoType(wrkMast.getIoType$()); // 入出库类型 vo.setSourceLocNo(wrkMast.getSourceLocNo$()); vo.setLocNo(wrkMast.getLocNo$()); vo.setCrnStatus(crnProtocol.getStatusType().desc); vo.setError(""); // todo vo.setError(""); // todo } } return R.ok().add(vo); src/main/java/com/zy/asrs/controller/StationController.java
New file @@ -0,0 +1,75 @@ package com.zy.asrs.controller; import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSONObject; import com.baomidou.mybatisplus.mapper.EntityWrapper; import com.zy.asrs.entity.BasDevp; import com.zy.asrs.service.BasDevpService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import com.core.common.Cools; import com.core.common.R; import com.zy.asrs.domain.param.StationCommandMoveParam; import com.zy.core.cache.MessageQueue; import com.zy.core.cache.SlaveConnection; import com.zy.core.enums.SlaveType; import com.zy.core.model.Task; import com.zy.core.model.command.StationCommand; import com.zy.core.thread.StationThread; import java.util.List; @RestController @RequestMapping("/station") public class StationController { @Autowired private BasDevpService basDevpService; @PostMapping("/command/move") public R commandMove(@RequestBody StationCommandMoveParam param) { if (Cools.isEmpty(param)) { return R.error("缺少参数"); } Integer stationId = param.getStationId(); Integer taskNo = param.getTaskNo(); Integer targetStationId = param.getTargetStationId(); JSONObject finalStation = null; List<BasDevp> basDevps = basDevpService.selectList(new EntityWrapper<BasDevp>()); for (BasDevp basDevp : basDevps) { List<JSONObject> list = JSON.parseArray(basDevp.getStationList(), JSONObject.class); for (JSONObject entity : list) { if(entity.getInteger("stationId").equals(stationId)){ finalStation = entity; break; } } if(finalStation != null){ break; } } if(finalStation == null){ return R.error("站点不存在"); } Integer devpNo = finalStation.getInteger("devpNo"); StationThread stationThread = (StationThread) SlaveConnection.get(SlaveType.Devp, devpNo); if (stationThread == null) { return R.error("线程不存在"); } StationCommand command = stationThread.getMoveCommand(taskNo, stationId, targetStationId, 0); MessageQueue.offer(SlaveType.Devp, devpNo, new Task(2, command)); return R.ok(); } } src/main/java/com/zy/asrs/domain/enums/StationStatusType.java
New file @@ -0,0 +1,45 @@ package com.zy.asrs.domain.enums; import com.zy.core.model.protocol.StationProtocol; /** * 站点状态枚举 */ public enum StationStatusType { // 自动 SITE_AUTO, // 非自动 SITE_UNAUTO, // 自动+有物+ID SITE_AUTO_RUN_ID, // 自动+有物 SITE_AUTO_RUN, // 自动+ID SITE_AUTO_ID, ; public static StationStatusType process(StationProtocol stationProtocol){ if (stationProtocol == null) { return null; } if (stationProtocol.isAutoing() && stationProtocol.isLoading() && stationProtocol.getTaskNo() > 0) { return SITE_AUTO_RUN_ID; } if (stationProtocol.isAutoing() && stationProtocol.isLoading()) { return SITE_AUTO_RUN; } if (stationProtocol.isAutoing() && stationProtocol.getTaskNo() > 0) { return SITE_AUTO_ID; } if (stationProtocol.isAutoing()) { return SITE_AUTO; } if (!stationProtocol.isAutoing()) { return SITE_UNAUTO; } return null; } } src/main/java/com/zy/asrs/domain/param/StationCommandMoveParam.java
New file @@ -0,0 +1,17 @@ package com.zy.asrs.domain.param; import lombok.Data; @Data public class StationCommandMoveParam { // 站点编号 private Integer stationId; // 目标站点编号 private Integer targetStationId; // 任务编号 private Integer taskNo; } src/main/java/com/zy/asrs/domain/vo/StationLatestDataVo.java
New file @@ -0,0 +1,46 @@ package com.zy.asrs.domain.vo; import lombok.Data; @Data public class StationLatestDataVo { // 站点编号 private Integer stationId; // 工作号 private Integer taskNo; // 目标站 private Integer targetStaNo; // 自动 private boolean autoing; // 有物 private boolean loading; // 可入 private boolean inEnable; // 可出 private boolean outEnable; // 空板信号 private boolean emptyMk; // 满托盘 private boolean fullPlt; // 托盘高度 private Integer palletHeight; //报警 private Integer error; //条码 private String barcode; private String stationStatus; } src/main/java/com/zy/asrs/utils/MapExcelUtils.java
@@ -323,6 +323,7 @@ HashMap<String, Object> mapData = data.get(k - 2).get(l - 2); mapData.put("bgColor", "merge"); mapData.put("value", map.get("value")); } } src/main/java/com/zy/common/model/NavigateNode.java
New file @@ -0,0 +1,64 @@ package com.zy.common.model; import lombok.Data; import lombok.ToString; import java.io.Serializable; import java.util.List; /** * A*寻路算法Node节点 */ @Data public class NavigateNode implements Comparable<NavigateNode>, Cloneable, Serializable { private int x;//坐标x private int y;//坐标y private int F;//综合花费的步数 private int G;//已经花费的步数 private int H;//将要花费的步数 private int value; @ToString.Exclude private NavigateNode Father;//父节点 private List<String> directionList;//行走方向 private String nodeValue;//节点数据 private String nodeType;//节点类型 public NavigateNode(int x, int y) { this.x = x; this.y = y; } //通过结点的坐标和目标结点的坐标可以计算出F, G, H三个属性 //需要传入这个节点的上一个节点和最终的结点 public void init_node(NavigateNode father, NavigateNode end) { this.Father = father; if (this.Father != null) { //走过的步数等于父节点走过的步数加一 this.G = father.G + this.G; } else { //父节点为空代表它是第一个结点 this.G = 0; } //以下计算方案为算法原始方案,没有去拐点方案。已被Solution计算时自动覆盖。 //计算通过现在的结点的位置和最终结点的位置计算H值(曼哈顿法:坐标分别取差值相加) this.H = Math.abs(this.x - end.x) + Math.abs(this.y - end.y); this.F = this.G + this.H; } @Override public int compareTo(NavigateNode o) { return Integer.compare(this.F, o.F); } @Override public NavigateNode clone() { try { return (NavigateNode) super.clone(); } catch (CloneNotSupportedException e) { e.printStackTrace(); } return null; } } src/main/java/com/zy/common/utils/NavigateSolution.java
New file @@ -0,0 +1,218 @@ package com.zy.common.utils; import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSONObject; import com.baomidou.mybatisplus.mapper.EntityWrapper; import com.core.common.SpringUtils; import com.core.exception.CoolException; import com.zy.asrs.entity.BasMap; import com.zy.asrs.service.BasMapService; import com.zy.common.model.NavigateNode; import com.zy.core.enums.MapNodeType; import java.util.*; /** * A*算法实现类 */ public class NavigateSolution { // Open表用优先队列 public PriorityQueue<NavigateNode> Open = new PriorityQueue<NavigateNode>(); //Close表用普通的数组 public ArrayList<NavigateNode> Close = new ArrayList<NavigateNode>(); //用来存放已经出现过的结点。 Map<String, Integer> bestGMap = new HashMap<>(); public List<List<NavigateNode>> getStationMap() { BasMapService basMapService = SpringUtils.getBean(BasMapService.class); BasMap basMap = basMapService.selectOne(new EntityWrapper<BasMap>().eq("lev", 1)); if (basMap == null) { throw new CoolException("地图不存在"); } List<List<JSONObject>> dataList = JSON.parseObject(basMap.getData(), List.class); List<List<NavigateNode>> navigateNodeList = new ArrayList<>(); for (int i = 0; i < dataList.size(); i++) { List<JSONObject> row = dataList.get(i); List<NavigateNode> navigateNodeRow = new ArrayList<>(); for (int j = 0; j < row.size(); j++) { JSONObject map = row.get(j); NavigateNode navigateNode = new NavigateNode(i, j); String nodeType = map.getString("type"); if(nodeType == null) { navigateNode.setValue(MapNodeType.DISABLE.id); }else if(nodeType.equals("devp") || nodeType.equals("merge")){ navigateNode.setValue(MapNodeType.NORMAL_PATH.id); JSONObject valueObj = JSON.parseObject(map.getString("value")); List<String> directionList = valueObj.getJSONArray("direction").toJavaList(String.class); navigateNode.setDirectionList(directionList); }else { navigateNode.setValue(MapNodeType.DISABLE.id); } navigateNode.setNodeType(nodeType); navigateNode.setNodeValue(map.getString("value")); navigateNodeRow.add(navigateNode); } navigateNodeList.add(navigateNodeRow); } return navigateNodeList; } public NavigateNode astarSearchJava(List<List<NavigateNode>> map, NavigateNode start, NavigateNode end) { // 清理上次搜索的状态,防止复用实例导致记录残留 this.Open.clear(); this.Close.clear(); this.bestGMap.clear(); //把第一个开始的结点加入到Open表中 this.Open.add(start); //主循环 while (Open.size() > 0) { //取优先队列顶部元素并且把这个元素从Open表中删除 NavigateNode current_node = Open.poll(); if (current_node.getX() == end.getX() && current_node.getY() == end.getY()) {//找到目标结点就返回 return current_node; } //将这个结点加入到Close表中 Close.add(current_node); //对当前结点进行扩展,得到一个四周结点的数组 ArrayList<NavigateNode> neighbour_node = extend_current_node(map, current_node); //对这个结点遍历,看是否有目标结点出现 for (NavigateNode node : neighbour_node) { // 已在关闭列表中的节点不再处理,避免父链反复改写形成环 if (Close.contains(node)) { continue; } // G + H + E (对启发函数增加去拐点方案calcNodeExtraCost) int gCost = calcNodeExtraCost(current_node, node, end); //进行计算对G, F, H 等值 node.setG(1 + gCost); node.init_node(current_node, end); node.setH(calcNodeCost(node, end)); node.setF(node.getG() + node.getH()); String key = node.getX() + "_" + node.getY(); Integer recordedG = bestGMap.get(key); // 仅当找到更小的代价时才更新与入Open,避免等价代价反复入队导致父链抖动 if (recordedG == null || node.getG() < recordedG) { bestGMap.put(key, node.getG()); Open.add(node); } } } //如果遍历完所有出现的结点都没有找到最终的结点,返回null return null; } public ArrayList<NavigateNode> extend_current_node(List<List<NavigateNode>> map, NavigateNode current_node) { //获取当前结点的x, y int x = current_node.getX(); int y = current_node.getY(); //如果当前结点的邻结点合法,就加入到neighbour_node ArrayList<NavigateNode> neighbour_node = new ArrayList<NavigateNode>(); if(current_node.getValue() == MapNodeType.DISABLE.id) { return neighbour_node; } List<String> directionList = current_node.getDirectionList(); if(directionList == null || directionList.size() == 0) { return neighbour_node; } for(String direction : directionList) { if(direction.equals("top")) { NavigateNode node = getValidNavigateNode(map, x - 1, y); if(node != null) { neighbour_node.add(node); } }else if(direction.equals("bottom")) { NavigateNode node = getValidNavigateNode(map, x + 1, y); if(node != null) { neighbour_node.add(node); } }else if(direction.equals("left")) { NavigateNode node = getValidNavigateNode(map, x, y - 1); if(node != null) { neighbour_node.add(node); } }else if(direction.equals("right")) { NavigateNode node = getValidNavigateNode(map, x, y + 1); if(node != null) { neighbour_node.add(node); } } } return neighbour_node; } public NavigateNode getValidNavigateNode(List<List<NavigateNode>> map, int x, int y) { if (x < 0 || x >= map.size() || y < 0 || y >= map.get(0).size()) { return null; } NavigateNode node = map.get(x).get(y); if(node.getValue() == MapNodeType.DISABLE.id) { return null; } return node; } public NavigateNode findStationNavigateNode(List<List<NavigateNode>> map, int stationId) { for(int x = 0; x < map.size(); x++) { for(int y = 0; y < map.get(0).size(); y++) { NavigateNode node = map.get(x).get(y); if("devp".equals(node.getNodeType())) { JSONObject valueObj = JSON.parseObject(node.getNodeValue()); if(valueObj.getInteger("stationId") == stationId) { return node; } } } } return null; } //------------------A*启发函数------------------// //计算通过现在的结点的位置和最终结点的位置计算H值(曼哈顿法:坐标分别取差值相加) private int calcNodeCost(NavigateNode node1, NavigateNode node2) { return Math.abs(node2.getX() - node1.getX()) + Math.abs(node2.getY() - node1.getY()); } //去除拐点算法,给直线增加优先级 private int calcNodeExtraCost(NavigateNode currNode, NavigateNode nextNode, NavigateNode endNode) { // 第一个点或直线点 if (currNode.getFather() == null || nextNode.getX() == currNode.getFather().getX() || nextNode.getY() == currNode.getFather().getY()) { return 0; } // 拐向终点的点 if (nextNode.getX() == endNode.getX() || nextNode.getY() == endNode.getY()) { return 1; } // 普通拐点 /* 拐点判断逻辑 拿到父节点和下一节点 通过判断父节点和下一节点的x数据和y数据都不相同时,则表明当前坐标是一个拐点 */ return 1; } //------------------A*启发函数-end------------------// } src/main/java/com/zy/common/utils/NavigateUtils.java
New file @@ -0,0 +1,69 @@ package com.zy.common.utils; import java.util.ArrayList; import java.util.Collections; import java.util.HashSet; import java.util.List; import org.springframework.stereotype.Component; import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSONObject; import com.core.exception.CoolException; import com.zy.common.model.NavigateNode; @Component public class NavigateUtils { public synchronized List<NavigateNode> calcByStationId(Integer startStationId, Integer endStationId) { NavigateSolution navigateSolution = new NavigateSolution(); List<List<NavigateNode>> stationMap = navigateSolution.getStationMap(); NavigateNode startNode = navigateSolution.findStationNavigateNode(stationMap, startStationId); if (startNode == null){ throw new CoolException("未找到该 起点 对应的节点"); } NavigateNode endNode = navigateSolution.findStationNavigateNode(stationMap, endStationId); if (endNode == null){ throw new CoolException("未找到该 终点 对应的节点"); } NavigateNode res_node = navigateSolution.astarSearchJava(stationMap, startNode, endNode); if (res_node == null) { throw new CoolException("未找到该路径"); } ArrayList<NavigateNode> list = new ArrayList<>(); // 使用 visited 集合防止父链出现环导致死循环,同时设置安全步数上限 HashSet<NavigateNode> visited = new HashSet<>(); int maxSteps = stationMap.size() * stationMap.get(0).size() + 5; // 安全上限 int steps = 0; while (res_node != null && visited.add(res_node) && steps++ < maxSteps) { list.add(res_node); res_node = res_node.getFather();//迭代操作 } if (steps >= maxSteps) { throw new CoolException("路径回溯超出安全上限,疑似存在父链循环"); } Collections.reverse(list); //将每个节点里面的fatherNode至为null(方便后续计算时父节点过多导致显示的节点太多) for (NavigateNode navigateNode : list) { //父节点设置为null,不影响计算结果,不影响后续操作。 //此操作仅为后续排查处理提供视觉方便。 navigateNode.setFather(null); } //去重 HashSet<Integer> set = new HashSet<>(); List<NavigateNode> fitlerList = new ArrayList<>(); for(NavigateNode navigateNode : list){ JSONObject valuObject = JSON.parseObject(navigateNode.getNodeValue()); if(set.add(valuObject.getInteger("stationId"))){ fitlerList.add(navigateNode); } } return fitlerList; } } src/main/java/com/zy/core/ServerBootstrap.java
@@ -9,6 +9,8 @@ import com.zy.core.cache.SlaveConnection; import com.zy.core.enums.SlaveType; import com.zy.core.thread.impl.ZySiemensCrnThread; import com.zy.core.thread.impl.ZyStationThread; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.scheduling.annotation.Async; @@ -95,6 +97,21 @@ SlaveConnection.put(SlaveType.Crn, deviceConfig.getDeviceNo(), thread); } News.info("初始化输送站........................................................"); List<DeviceConfig> devpList = deviceConfigService.selectList(new EntityWrapper<DeviceConfig>() .eq("device_type", String.valueOf(SlaveType.Devp))); for (DeviceConfig deviceConfig : devpList) { ThreadHandler thread = null; if (deviceConfig.getThreadImpl().equals("ZyStationThread")) { thread = new ZyStationThread(deviceConfig, redisUtil); } else { throw new CoolException("未知的线程实现"); } new Thread(thread).start(); SlaveConnection.put(SlaveType.Devp, deviceConfig.getDeviceNo(), thread); } } src/main/java/com/zy/core/model/protocol/StationProtocol.java
New file @@ -0,0 +1,57 @@ package com.zy.core.model.protocol; import lombok.Data; @Data public class StationProtocol { // 站点编号 private Integer stationId; // ---------------------------------------------------------------- // 工作号 private Integer taskNo = 0; // ---------------------------------------------------------------- // 目标站 private Integer targetStaNo; // ---------------------------------------------------------------- // 自动 private boolean autoing; // 有物 private boolean loading; // 可入 private boolean inEnable; // 可出 private boolean outEnable; // 空板信号 private boolean emptyMk; // 满托盘 private boolean fullPlt; // 托盘高度 private Integer palletHeight; //报警 private Integer error; //条码 private String barcode; @Override public StationProtocol clone() { try { return (StationProtocol) super.clone(); } catch (CloneNotSupportedException e) { e.printStackTrace(); } return null; } } src/main/java/com/zy/core/network/entity/ZyStationStatusEntity.java
@@ -35,9 +35,6 @@ // 满托盘 private boolean fullPlt; // 锁定标记 private boolean pakMk = true; // 托盘高度 private Integer palletHeight; src/main/java/com/zy/core/network/fake/ZyStationFakeConnect.java
@@ -1,12 +1,17 @@ package com.zy.core.network.fake; import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSONObject; import com.core.common.SpringUtils; import com.zy.asrs.entity.DeviceConfig; import com.zy.common.model.NavigateNode; import com.zy.common.utils.NavigateUtils; import com.zy.core.model.CommandResponse; import com.zy.core.model.command.StationCommand; import com.zy.core.network.api.ZyStationConnectApi; import com.zy.core.network.entity.ZyStationStatusEntity; import java.util.Collections; import java.util.ArrayList; import java.util.List; import java.util.concurrent.ExecutorService; @@ -17,17 +22,14 @@ */ public class ZyStationFakeConnect implements ZyStationConnectApi { private ZyStationStatusEntity status; private List<ZyStationStatusEntity> statusList = new ArrayList<>(); private final DeviceConfig deviceConfig; private final ExecutorService executor = Executors.newSingleThreadExecutor(); // 允许并行执行多个命令任务(固定线程池)。如需更高并发可调整大小。 private final ExecutorService executor = Executors .newFixedThreadPool(Math.max(2, Runtime.getRuntime().availableProcessors())); public ZyStationFakeConnect(DeviceConfig deviceConfig) { this.deviceConfig = deviceConfig; this.status = JSON.parseObject(deviceConfig.getFakeInitStatus(), ZyStationStatusEntity.class); if (this.status == null) { this.status = new ZyStationStatusEntity(); this.status.setStationId(deviceConfig.getDeviceNo()); } } @Override @@ -37,43 +39,129 @@ @Override public boolean disconnect() { executor.shutdownNow(); return true; } @Override public List<ZyStationStatusEntity> getStatus() { return Collections.singletonList(status); if (this.statusList.isEmpty()) { this.statusList = JSON.parseArray(deviceConfig.getFakeInitStatus(), ZyStationStatusEntity.class); for (ZyStationStatusEntity status : this.statusList) { status.setAutoing(true);// 模拟自动运行 status.setLoading(false);// 模拟有物 status.setInEnable(true);// 模拟可入 status.setOutEnable(true);// 模拟可出 status.setEmptyMk(false);// 模拟空板信号 status.setFullPlt(false);// 模拟满托盘 status.setPalletHeight(0);// 模拟托盘高度为0 status.setError(0);// 模拟无报警 status.setBarcode("");// 模拟无条码 } } return this.statusList; } @Override public CommandResponse sendCommand(StationCommand command) { CommandResponse response = new CommandResponse(false); executor.submit(() -> handleCommand(command)); response.setResult(true); return response; executor.submit(() -> { try { handleCommand(command); } catch (Exception e) { e.printStackTrace(); } }); return new CommandResponse(true, "命令已受理(异步执行)"); } private void handleCommand(StationCommand command) { // 简单的模拟:设置工作号和目标站,并模拟有物/可入/可出状态切换 this.status.setTaskNo(command.getTaskNo()); this.status.setTargetStaNo(command.getTargetStaNo()); NavigateUtils navigateUtils = SpringUtils.getBean(NavigateUtils.class); if (navigateUtils == null) { return; } // 模拟到站过程 this.status.setAutoing(true); this.status.setLoading(true); sleep(1000); Integer taskNo = command.getTaskNo(); Integer stationId = command.getStationId(); Integer targetStationId = command.getTargetStaNo(); // 模拟放下托盘 this.status.setInEnable(true); this.status.setOutEnable(false); sleep(1000); List<NavigateNode> navigateNodes = null; // 完成任务,复位状态 this.status.setLoading(false); this.status.setAutoing(false); this.status.setTaskNo(0); this.status.setInEnable(false); this.status.setOutEnable(true); try { navigateNodes = navigateUtils.calcByStationId(stationId, targetStationId); } catch (Exception e) { e.printStackTrace(); } if (navigateNodes == null) { return; } Integer lastStationId = null; for (int i = 0; i < navigateNodes.size(); i++) { NavigateNode navigateNode = navigateNodes.get(i); JSONObject valueObject = JSON.parseObject(navigateNode.getNodeValue()); Integer currentStationId = valueObject.getInteger("stationId"); ZyStationStatusEntity status = statusList.stream() .filter(item -> item.getStationId().equals(currentStationId)).findFirst().orElse(null); if (status == null) { continue; } try { while (true) { ZyStationStatusEntity nextStatus = statusList.stream() .filter(item -> item.getStationId().equals(currentStationId)).findFirst().orElse(null); if (nextStatus == null) { continue; } if (nextStatus.getTaskNo() == 0) { break; } sleep(100); } } catch (Exception e) { continue; } synchronized (status) { status.setTaskNo(taskNo); status.setTargetStaNo(targetStationId); status.setLoading(true); } if (lastStationId != null) { Integer finalLastStationId = lastStationId; ZyStationStatusEntity lastStatus = statusList.stream() .filter(item -> item.getStationId().equals(finalLastStationId)).findFirst().orElse(null); if (lastStatus != null) { synchronized (lastStatus) { lastStatus.setTaskNo(0); lastStatus.setTargetStaNo(0); lastStatus.setLoading(false); } } } lastStationId = currentStationId; sleep(1000); } sleep(10000); if (lastStationId != null) { Integer finalLastStationId = lastStationId; ZyStationStatusEntity lastStatus = statusList.stream() .filter(item -> item.getStationId().equals(finalLastStationId)).findFirst().orElse(null); if (lastStatus != null) { synchronized (lastStatus) { lastStatus.setTaskNo(0); lastStatus.setTargetStaNo(0); lastStatus.setLoading(false); } } } } private void sleep(long ms) { src/main/java/com/zy/core/network/real/ZyStationRealConnect.java
@@ -19,8 +19,6 @@ import com.zy.core.model.command.StationCommand; import com.zy.core.network.api.ZyStationConnectApi; import com.zy.core.network.entity.ZyStationStatusEntity; import java.util.ArrayList; import java.util.Collections; import java.util.List; src/main/java/com/zy/core/thread/StationThread.java
@@ -3,14 +3,14 @@ import com.zy.core.ThreadHandler; import com.zy.core.model.CommandResponse; import com.zy.core.model.command.StationCommand; import com.zy.core.network.entity.ZyStationStatusEntity; import com.zy.core.model.protocol.StationProtocol; import java.util.List; public interface StationThread extends ThreadHandler{ public interface StationThread extends ThreadHandler { List<ZyStationStatusEntity> getStatus(); List<StationProtocol> getStatus(); StationCommand getMoveCommand(); StationCommand getMoveCommand(Integer taskNo, Integer stationId, Integer targetStationId, Integer palletSize); CommandResponse sendCommand(StationCommand command); src/main/java/com/zy/core/thread/impl/ZyStationThread.java
@@ -1,13 +1,34 @@ package com.zy.core.thread.impl; import HslCommunication.Profinet.Siemens.SiemensPLCS; import HslCommunication.Profinet.Siemens.SiemensS7Net; import com.alibaba.fastjson.JSONObject; import com.baomidou.mybatisplus.mapper.EntityWrapper; import com.zy.asrs.entity.BasDevp; import com.zy.asrs.service.BasDevpService; import com.zy.core.network.DeviceConnectPool; import com.zy.core.thread.StationThread; import com.alibaba.fastjson.JSON; import com.core.common.DateUtils; import com.core.common.SpringUtils; import com.zy.asrs.entity.DeviceConfig; import com.zy.asrs.entity.DeviceDataLog; import com.zy.asrs.service.DeviceDataLogService; import com.zy.common.utils.RedisUtil; import com.zy.core.network.ZyStationConnectDriver; import com.zy.core.cache.MessageQueue; import com.zy.core.cache.OutputQueue; import com.zy.core.enums.SlaveType; import com.zy.core.model.CommandResponse; import com.zy.core.model.Task; import com.zy.core.model.command.StationCommand; import com.zy.core.model.protocol.StationProtocol; import com.zy.core.network.entity.ZyStationStatusEntity; import java.text.MessageFormat; import java.util.ArrayList; import java.util.Collections; import java.util.Date; import java.util.List; import lombok.Data; @@ -20,9 +41,11 @@ @Slf4j public class ZyStationThread implements Runnable, StationThread { private List<StationProtocol> statusList = new ArrayList<>(); private DeviceConfig deviceConfig; private RedisUtil redisUtil; private ZyStationConnectDriver zyStationConnectDriver; private long deviceDataLogTime = System.currentTimeMillis(); public ZyStationThread(DeviceConfig deviceConfig, RedisUtil redisUtil) { this.deviceConfig = deviceConfig; @@ -30,7 +53,103 @@ } @Override @SuppressWarnings("InfiniteLoopStatement") public void run() { this.connect(); while (true) { try { int step = 1; Task task = MessageQueue.poll(SlaveType.Devp, deviceConfig.getDeviceNo()); if (task != null) { step = task.getStep(); } switch (step) { // 读数据 case 1: readStatus(); break; case 2: sendCommand((StationCommand) task.getData()); break; default: break; } Thread.sleep(200); } catch (Exception e) { e.printStackTrace(); } } } private void readStatus() { if (zyStationConnectDriver == null) { return; } if(statusList.isEmpty()) { BasDevpService basDevpService = SpringUtils.getBean(BasDevpService.class); if (basDevpService == null) { return; } BasDevp basDevp = basDevpService .selectOne(new EntityWrapper<BasDevp>().eq("devp_no", deviceConfig.getDeviceNo())); if (basDevp == null) { return; } List<ZyStationStatusEntity> list = JSONObject.parseArray(basDevp.getStationList(), ZyStationStatusEntity.class); for (ZyStationStatusEntity entity : list) { StationProtocol stationProtocol = new StationProtocol(); stationProtocol.setStationId(entity.getStationId()); statusList.add(stationProtocol); } } List<ZyStationStatusEntity> zyStationStatusEntities = zyStationConnectDriver.getStatus(); for (ZyStationStatusEntity statusEntity : zyStationStatusEntities) { for (StationProtocol stationProtocol : statusList) { if(stationProtocol.getStationId().equals(statusEntity.getStationId())) { stationProtocol.setTaskNo(statusEntity.getTaskNo()); stationProtocol.setTargetStaNo(statusEntity.getTargetStaNo()); stationProtocol.setAutoing(statusEntity.isAutoing()); stationProtocol.setLoading(statusEntity.isLoading()); stationProtocol.setInEnable(statusEntity.isInEnable()); stationProtocol.setOutEnable(statusEntity.isOutEnable()); stationProtocol.setEmptyMk(statusEntity.isEmptyMk()); stationProtocol.setFullPlt(statusEntity.isFullPlt()); stationProtocol.setPalletHeight(statusEntity.getPalletHeight()); stationProtocol.setError(statusEntity.getError()); stationProtocol.setBarcode(statusEntity.getBarcode()); } } } OutputQueue.DEVP.offer(MessageFormat.format("【{0}】[id:{1}] <<<<< 实时数据更新成功",DateUtils.convert(new Date()), deviceConfig.getDeviceNo())); if (System.currentTimeMillis() - deviceDataLogTime > 1000 * 1) { //采集时间超过1s,保存一次数据记录 //保存数据记录 DeviceDataLogService deviceDataLogService = SpringUtils.getBean(DeviceDataLogService.class); DeviceDataLog deviceDataLog = new DeviceDataLog(); deviceDataLog.setOriginData(JSON.toJSONString(zyStationStatusEntities)); deviceDataLog.setWcsData(JSON.toJSONString(statusList)); deviceDataLog.setType(String.valueOf(SlaveType.Devp)); deviceDataLog.setDeviceNo(deviceConfig.getDeviceNo()); deviceDataLog.setCreateTime(new Date()); deviceDataLogService.insert(deviceDataLog); //更新采集时间 deviceDataLogTime = System.currentTimeMillis(); } } @Override public boolean connect() { SiemensS7Net siemensS7Net = new SiemensS7Net(SiemensPLCS.S1200, deviceConfig.getIp()); zyStationConnectDriver = new ZyStationConnectDriver(siemensS7Net, deviceConfig); new Thread(zyStationConnectDriver).start(); DeviceConnectPool.put(SlaveType.Devp, deviceConfig.getDeviceNo(), zyStationConnectDriver); return true; } @@ -39,24 +158,24 @@ } @Override public List<ZyStationStatusEntity> getStatus() { if (zyStationConnectDriver == null) { return Collections.emptyList(); } return zyStationConnectDriver.getStatus(); public List<StationProtocol> getStatus() { return statusList; } @Override public StationCommand getMoveCommand() { return null; public StationCommand getMoveCommand(Integer taskNo, Integer stationId, Integer targetStationId, Integer palletSize) { StationCommand stationCommand = new StationCommand(); stationCommand.setTaskNo(taskNo); stationCommand.setStationId(stationId); stationCommand.setTargetStaNo(targetStationId); stationCommand.setPalletSize(palletSize); return stationCommand; } @Override public CommandResponse sendCommand(StationCommand command) { return new CommandResponse(true); CommandResponse commandResponse = zyStationConnectDriver.sendCommand(command); return commandResponse; } @Override public void run() { } } src/main/webapp/components/DevpCard.js
New file @@ -0,0 +1,139 @@ Vue.component("devp-card", { template: ` <div> <div style="display: flex;margin-bottom: 10px;"> <div style="width: 100%;">输送监控</div> <div style="width: 100%;text-align: right;display: flex;"><el-input size="mini" v-model="searchStationId" placeholder="请输入站号"></el-input><el-button @click="getDevpStateInfo" size="mini">查询</el-button></div> </div> <div style="margin-bottom: 10px;"> <div style="margin-bottom: 5px;"> <el-button v-if="showControl" @click="openControl" size="mini">关闭控制中心</el-button> <el-button v-else @click="openControl" size="mini">打开控制中心</el-button> </div> <div v-if="showControl" style="display: flex;justify-content: space-between;flex-wrap: wrap;"> <div style="margin-bottom: 10px;width: 33%;"><el-input size="mini" v-model="controlParam.stationId" placeholder="站号"></el-input></div> <div style="margin-bottom: 10px;width: 33%;"><el-input size="mini" v-model="controlParam.taskNo" placeholder="工作号"></el-input></div> <div style="margin-bottom: 10px;width: 33%;"><el-input size="mini" v-model="controlParam.targetStationId" placeholder="目标站"></el-input></div> <div style="margin-bottom: 10px;"><el-button @click="controlCommand()" size="mini">下发</el-button></div> </div> </div> <el-collapse v-model="activeNames"> <el-collapse-item v-for="(item) in stationList" :name="item.stationId"> <template slot="title"> <div style="width: 100%;display: flex;"> <div style="width: 50%;">{{ item.stationId }}站</div> <div style="width: 50%;text-align: right;"> <el-tag v-if="item.autoing" type="success" size="small">自动</el-tag> <el-tag v-else type="warning" size="small">手动</el-tag> </div> </div> </template> <el-descriptions border direction="vertical"> <el-descriptions-item label="编号">{{ item.stationId }}</el-descriptions-item> <el-descriptions-item label="工作号">{{ item.taskNo }}</el-descriptions-item> <el-descriptions-item label="目标站">{{ item.targetStaNo }}</el-descriptions-item> <el-descriptions-item label="模式">{{ item.autoing ? '自动' : '手动' }}</el-descriptions-item> <el-descriptions-item label="有物">{{ item.loading ? '有' : '无' }}</el-descriptions-item> <el-descriptions-item label="可入">{{ item.inEnable ? 'Y' : 'N' }}</el-descriptions-item> <el-descriptions-item label="可出">{{ item.outEnable ? 'Y' : 'N' }}</el-descriptions-item> <el-descriptions-item label="空板信号">{{ item.emptyMk ? 'Y' : 'N' }}</el-descriptions-item> <el-descriptions-item label="满板信号">{{ item.fullPlt ? 'Y' : 'N' }}</el-descriptions-item> <el-descriptions-item label="托盘高度">{{ item.palletHeight }}</el-descriptions-item> <el-descriptions-item label="条码">{{ item.barcode }}</el-descriptions-item> <el-descriptions-item label="故障代码">{{ item.error }}</el-descriptions-item> </el-descriptions> </el-collapse-item> </el-collapse> </div> `, props: ["param"], data() { return { stationList: [], activeNames: "", searchStationId: "", showControl: true, controlParam: { stationId: "", taskNo: "", targetStationId: "", }, }; }, created() { setInterval(() => { this.getDevpStateInfo(); }, 1000); }, watch: { param: { handler(newVal, oldVal) { if (newVal.stationId != 0) { this.activeNames = newVal.stationId; this.searchStationId = newVal.stationId; } }, deep: true, // 深度监听嵌套属性 immediate: true, // 立即触发一次(可选) }, }, methods: { getDevpStateInfo() { let that = this; $.ajax({ url: baseUrl + "/console/latest/data/station", headers: { token: localStorage.getItem("token"), }, method: "post", success: (res) => { // 堆垛机信息表获取 if (res.code == 200) { let list = res.data; if (that.searchStationId == "") { that.stationList = list; } else { let tmp = []; list.forEach((item) => { if (item.stationId == that.searchStationId) { tmp.push(item); } }); that.stationList = tmp; } } }, }); }, openControl() { this.showControl = !this.showControl; }, controlCommand() { let that = this; //下发命令 $.ajax({ url: baseUrl + "/station/command/move", headers: { token: localStorage.getItem("token"), }, contentType: "application/json", method: "post", data: JSON.stringify(that.controlParam), success: (res) => { if (res.code == 200) { that.$message({ message: res.msg, type: "success", }); } else { that.$message({ message: res.msg, type: "warning", }); } }, }); }, }, }); src/main/webapp/components/WatchCrnCard.js
@@ -7,7 +7,8 @@ </div> <div style="margin-bottom: 10px;"> <div style="margin-bottom: 5px;"> <el-button @click="openControl" size="mini">控制中心</el-button> <el-button v-if="showControl" @click="openControl" size="mini">关闭控制中心</el-button> <el-button v-else @click="openControl" size="mini">打开控制中心</el-button> </div> <div v-if="showControl" style="display: flex;justify-content: space-between;flex-wrap: wrap;"> <div style="margin-bottom: 10px;width: 33%;"><el-input size="mini" v-model="controlParam.crnNo" placeholder="堆垛机号"></el-input></div> @@ -64,7 +65,7 @@ crnList: [], activeNames: "", searchCrnNo: "", showControl: true, showControl: false, controlParam: { crnNo: "", sourceLocNo: "", src/main/webapp/views/watch/console.html
@@ -21,7 +21,9 @@ <el-tab-pane label="堆垛机" name="crn"> <watch-crn-card :param="crnParam"></watch-crn-card> </el-tab-pane> <el-tab-pane label="输送线" name="devp">输送线</el-tab-pane> <el-tab-pane label="输送站" name="devp"> <devp-card :param="devpParam"></devp-card> </el-tab-pane> <el-tab-pane label="RGV" name="rgv">RGV</el-tab-pane> <el-tab-pane label="地图配置" name="mapSetting"> <map-setting-card :param="mapSettingParam"></map-setting-card> @@ -45,7 +47,7 @@ <div class="shelf">{{col.shelfIdx}}</div> </div> <div v-else-if="col.type == 'devp'"> <div class="site" :style="{height: col.rowPx}" :id="'site-' + col.value" @click="openSite(col.value)">{{col.value}}</div> <div class="site" :style="{height: col.rowPx}" :id="'site-' + getStationId(col.value)" @click="openSite(getStationId(col.value))">{{getStationId(col.value)}}</div> </div> <div v-else-if="col.type == 'rgv'" style="position: relative;"> <div class="rgv-item" v-if="getDeviceNo(col.value) != -1" :style="{width: col.width}" :id="'rgv-' + getDeviceNo(col.value)" @click="openRgv(getDeviceNo(col.value))">{{getDeviceNo(col.value)}}</div> @@ -71,6 +73,7 @@ </div> <script src="../../components/WatchCrnCard.js"></script> <script src="../../components/DevpCard.js"></script> <script src="../../components/MapSettingCard.js"></script> <script> var app = new Vue({ @@ -88,6 +91,9 @@ }, mapSettingParam: { zoom: 70 }, devpParam: { stationId: 0 } }, created() { @@ -101,11 +107,11 @@ this.getMap() this.getSystemRunningStatus() //获取系统运行状态 // this.consoleInterval = setInterval(() => { // this.getCrnInfo() //获取堆垛机数据 // this.getSiteInfo() //获取输送站点数据 // this.getRgvInfo() //获取RGV数据 // }, 1000) this.consoleInterval = setInterval(() => { this.getCrnInfo() //获取堆垛机数据 this.getSiteInfo() //获取输送站点数据 this.getRgvInfo() //获取RGV数据 }, 1000) }, //获取地图数据 getMap() { @@ -113,7 +119,10 @@ let colPx = 35; $.ajax({ url: "./test.json", url: baseUrl + "/basMap/lev/1/auth", headers: { 'token': localStorage.getItem('token') }, method: "get", success: (res) => { let data = res.data; @@ -166,47 +175,25 @@ }) }, openSite(id) { this.siteWindow = true; //打开站点信息弹窗 $(".detailed").empty(); $('.detailed').append(id + '站点详细信息'); $.ajax({ url: baseUrl + "/console/site/detail", headers: { 'token': localStorage.getItem('token') }, data: { siteId: id }, method: 'post', success: function(res) { for (var val in res.data) { var find = $("#siteWindow").find(":input[name='" + val + "']"); if (find[0].type === 'text') { find.val(res.data[val]); } else if (find[0].type === 'checkbox') { find.attr("checked", res.data[val] === 'Y'); } } } }) this.devpParam.stationId = id; }, getSiteInfo() { //获取输送站点数据 $.ajax({ url: baseUrl + "/console/latest/data/site", url: baseUrl + "/console/latest/data/station", headers: {'token': localStorage.getItem('token')}, method: 'POST', success: function (res) { console.log(res) if (res.code === 200) { var sites = res.data; for (var i = 0; i < sites.length; i++){ var siteEl = $("#site-"+sites[i].siteId); siteEl.attr("class", "site " + sites[i].siteStatus); if (sites[i].workNo != null && sites[i].workNo>0) { siteEl.html(sites[i].siteId + "[" + sites[i].workNo + "]"); var siteEl = $("#site-"+sites[i].stationId); siteEl.attr("class", "site " + sites[i].stationStatus); if (sites[i].taskNo != null && sites[i].taskNo>0) { siteEl.html(sites[i].stationId + "[" + sites[i].taskNo + "]"); } else { siteEl.html(sites[i].siteId); siteEl.html(sites[i].stationId); } } } else if (res.code === 403) { @@ -454,6 +441,17 @@ return -1; } }, getStationId(obj) { if (this.isJson(obj)) { let data = JSON.parse(obj) if (data.stationId == null || data.stationId == undefined) { return -1; } return data.stationId; }else { return -1; } }, getTrackSiteNo(obj) { if (this.isJson(obj)) { let data = JSON.parse(obj) src/main/webapp/views/watch/test.json
File was deleted