src/main/java/com/zy/asrs/controller/RgvController.java
New file @@ -0,0 +1,336 @@ package com.zy.asrs.controller; import com.baomidou.mybatisplus.mapper.EntityWrapper; import com.core.annotations.ManagerAuth; import com.core.common.R; import com.core.exception.CoolException; import com.zy.asrs.domain.enums.RgvStatusType; import com.zy.asrs.domain.param.RgvOperatorParam; import com.zy.asrs.domain.vo.*; import com.zy.asrs.entity.*; import com.zy.asrs.mapper.BasRgvErrMapper; import com.zy.asrs.service.BasRgvService; import com.zy.asrs.service.LocMastService; import com.zy.asrs.service.WrkMastService; import com.zy.asrs.service.impl.MainServiceImpl; import com.zy.asrs.utils.VersionUtils; import com.zy.core.cache.MessageQueue; import com.zy.core.cache.OutputQueue; import com.zy.core.cache.SlaveConnection; import com.zy.core.enums.RgvModeType; import com.zy.core.enums.RgvTaskModeType; import com.zy.core.enums.SlaveType; import com.zy.core.model.RgvSlave; import com.zy.core.model.Task; import com.zy.core.model.command.RgvCommand; import com.zy.core.model.protocol.RgvProtocol; import com.zy.core.properties.SlaveProperties; import com.zy.core.thread.RgvThread; 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.RequestMapping; import org.springframework.web.bind.annotation.RestController; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; /** * RGV接口 * Created by vincent on 2020-06-01 */ @Slf4j @RestController @RequestMapping("/rgv") public class RgvController { @Autowired private SlaveProperties slaveProperties; @Autowired private WrkMastService wrkMastService; @Autowired private BasRgvErrMapper basRgvErrMapper; @Autowired private BasRgvService basRgvService; @Autowired private MainServiceImpl mainService; @Autowired private LocMastService locMastService; @PostMapping("/table/rgv/state") @ManagerAuth(memo = "RGV信息表") public R rgvStateTable(){ List<RgvStateTableVo> list = new ArrayList<>(); List<BasRgv> rgvs = basRgvService.selectList(new EntityWrapper<BasRgv>().orderBy("rgv_no")); for (BasRgv basRgv : rgvs) { // 表格行 RgvStateTableVo vo = new RgvStateTableVo(); vo.setRgvNo(basRgv.getRgvNo()); // RGV号 list.add(vo); // 获取RGV信息 RgvThread rgvThread = (RgvThread) SlaveConnection.get(SlaveType.Rgv, basRgv.getRgvNo()); if (rgvThread == null) { continue; } RgvProtocol rgvProtocol = rgvThread.getRgvProtocol(); if (rgvProtocol == null) { continue; } vo.setStatusType(rgvProtocol.modeType.desc); // 模式状态 vo.setStatus(rgvProtocol.getStatusType().desc); // 状态 vo.setWorkNo1(rgvProtocol.getTaskNo1()); // 工位1任务号 vo.setStatus1(rgvProtocol.getStatusType1().desc); // 工位1状态 vo.setLoading1(rgvProtocol.getLoaded1()==1?"有物":"无物"); // 工位1有物 vo.setRgvPos(rgvProtocol.getRgvPos()); vo.setWalkPos(rgvProtocol.getWalkPos()==1?"不在定位":"在定位"); vo.setWorkNo2(rgvProtocol.getTaskNo2()); // 工位2任务号 vo.setStatus2(rgvProtocol.getStatusType2().desc); // 工位2状态 vo.setLoading2(rgvProtocol.getLoaded2()==1?"有物":"无物"); // 工位2有物 vo.setWarnCode(String.valueOf(rgvProtocol.getAlarm())); if (rgvProtocol.getAlarm() > 0) { BasRgvErr rgvErr = basRgvErrMapper.selectById(rgvProtocol.getAlarm()); vo.setAlarm(rgvErr==null?"未知异常":rgvErr.getErrName()); } } return R.ok().add(list); } @PostMapping("/table/rgv/msg") @ManagerAuth(memo = "RGV数据表") public R rgvMsgTable(){ List<RgvMsgTableVo> list = new ArrayList<>(); List<BasRgv> rgvs = basRgvService.selectList(new EntityWrapper<BasRgv>().orderBy("rgv_no")); for (BasRgv basRgv : rgvs) { // 表格行 RgvMsgTableVo vo = new RgvMsgTableVo(); vo.setRgvNo(basRgv.getRgvNo()); // RGV号 list.add(vo); // 获取RGV信息 RgvThread rgvThread = (RgvThread) SlaveConnection.get(SlaveType.Crn, basRgv.getRgvNo()); if (rgvThread == null) { continue; } RgvProtocol rgvProtocol = rgvThread.getRgvProtocol(); if (rgvProtocol == null) { continue; } vo.setWorkNo1(rgvProtocol.getTaskNo1()); // 任务号 if (rgvProtocol.getTaskNo1()>0) { WrkMast wrkMast = wrkMastService.selectById(rgvProtocol.getTaskNo1()); if (wrkMast != null) { vo.setStatus(RgvStatusType.process(wrkMast.getIoType()).getDesc()); // 模式状态 vo.setSourceStaNo(wrkMast.getSourceStaNo$()); // 源站 vo.setStaNo(wrkMast.getStaNo$()); // 目标站 vo.setSourceLocNo(wrkMast.getSourceLocNo()); // 源库位 vo.setLocNo(wrkMast.getLocNo()); // 目标库位 } } else { vo.setStatus(rgvProtocol.modeType.equals(RgvModeType.AUTO)? rgvProtocol.modeType.desc: RgvModeType.HAND.desc); // 模式状态 } vo.setXspeed(rgvProtocol.getXSpeed()); // 走行速度(m/min) vo.setXdistance(rgvProtocol.getXDistance()); // 走行距离(Km) vo.setXduration(rgvProtocol.getXDuration()); // 走行时长(H) } return R.ok().add(list); } @PostMapping("/output/site") @ManagerAuth(memo = "RGV报文日志输出") public R rgvOutput(){ StringBuilder str = new StringBuilder(); String s; int i = 0; while((s = OutputQueue.CRN.poll()) != null && i <=10) { str.append("\n").append(s); i++; } return R.ok().add(str.toString()); } @GetMapping("/demo/status") public R demoStatus(){ List<Map<String, Object>> res = new ArrayList<>(); for (RgvSlave rgvSlave : slaveProperties.getRgv()) { Map<String, Object> map = new HashMap<>(); map.put("rgvNo", rgvSlave.getId()); map.put("demo", rgvSlave.getDemo()); res.add(map); } return R.ok().add(res); } /****************************************************************/ /************************** 手动操作 ******************************/ /****************************************************************/ @ManagerAuth(memo = "取放货") @PostMapping("/operator/put") public R rgvFetchPut(RgvOperatorParam param){ RgvCommand command = new RgvCommand(); command.setRgvNo(param.getRgvNo()); // RGV编号 command.setAckFinish1((short) 0); // 任务完成确认位 command.setTaskNo1((short) 0); // 工作号 command.setTaskMode1(RgvTaskModeType.FETCH_PUT); // 任务模式: 取放货 command.setSourceStaNo1(param.getSourceStaNo1()); // 源站 command.setDestinationStaNo1(param.getStaNo1()); // 目标站 command.setAckFinish2((short) 0); // 任务完成确认位 command.setTaskNo2((short) 0); // 工作号 command.setTaskMode2(RgvTaskModeType.FETCH_PUT); // 任务模式: 取放货 command.setSourceStaNo2(param.getSourceStaNo2()); // 源站 command.setDestinationStaNo2(param.getStaNo2()); // 目标站 command.setCommand((short) 0); return rgvControl(command)?R.ok():R.error(); } @ManagerAuth(memo = "取货") @PostMapping("/operator/take") public R rgvFetch(RgvOperatorParam param){ RgvCommand command = new RgvCommand(); command.setRgvNo(param.getRgvNo()); // RGV编号 command.setAckFinish1((short) 0); // 任务完成确认位 command.setTaskNo1((short) 0); // 工作号 command.setTaskMode1(RgvTaskModeType.FETCH); // 任务模式: 取货 command.setSourceStaNo1(param.getSourceStaNo1()); // 源站 command.setDestinationStaNo1(param.getStaNo1()); // 目标站 command.setAckFinish2((short) 0); // 任务完成确认位 command.setTaskNo2((short) 0); // 工作号 command.setTaskMode2(RgvTaskModeType.FETCH_PUT); // 任务模式: 取放货 command.setSourceStaNo2(param.getSourceStaNo2()); // 源站 command.setDestinationStaNo2(param.getStaNo2()); // 目标站 command.setCommand((short) 0); return rgvControl(command)?R.ok():R.error(); } @ManagerAuth(memo = "放货") @PostMapping("/operator/stockMove") public R rgvPut(RgvOperatorParam param){ RgvCommand command = new RgvCommand(); command.setRgvNo(param.getRgvNo()); // RGV编号 command.setAckFinish1((short) 0); // 任务完成确认位 command.setTaskNo1((short) 0); // 工作号 command.setTaskMode1(RgvTaskModeType.PUT); // 任务模式: 放货 command.setSourceStaNo1(param.getSourceStaNo1()); // 源站 command.setDestinationStaNo1(param.getStaNo1()); // 目标站 command.setAckFinish2((short) 0); // 任务完成确认位 command.setTaskNo2((short) 0); // 工作号 command.setTaskMode2(RgvTaskModeType.FETCH_PUT); // 任务模式: 取放货 command.setSourceStaNo2(param.getSourceStaNo2()); // 源站 command.setDestinationStaNo2(param.getStaNo2()); // 目标站 command.setCommand((short) 0); return rgvControl(command)?R.ok():R.error(); } @ManagerAuth(memo = "任务完成") @PostMapping("/operator/taskComplete") public R rgvTaskComplete(RgvOperatorParam param){ RgvCommand command = new RgvCommand(); command.setRgvNo(param.getRgvNo()); // RGV编号 command.setAckFinish1((short) 1); // 任务完成确认位 command.setTaskNo1((short) 0); // 工作号 command.setTaskMode1(RgvTaskModeType.NONE); // 任务模式 command.setSourceStaNo1((short) 0); // 源站 command.setDestinationStaNo1((short) 0); // 目标站 command.setAckFinish2((short) 1); // 任务完成确认位 command.setTaskNo2((short) 0); // 工作号 command.setTaskMode2(RgvTaskModeType.NONE); // 任务模式 command.setSourceStaNo2((short) 0); // 源站 command.setDestinationStaNo2((short) 0); // 目标站 command.setCommand((short) 0); return rgvControl(command)?R.ok():R.error(); } @ManagerAuth(memo = "清除命令") @PostMapping("/operator/clearCommand") public R rgvClearCommand(RgvOperatorParam param){ if (param.getRgvNo() == null) { throw new CoolException("请选择RGV号"); } RgvCommand command = new RgvCommand(); command.setRgvNo(param.getRgvNo()); // RGV编号 command.setAckFinish1((short) 0); // 任务完成确认位 command.setTaskNo1((short) 0); // 工作号 command.setTaskMode1(RgvTaskModeType.NONE); // 任务模式 command.setSourceStaNo1((short) 0); // 源站 command.setDestinationStaNo1((short) 0); // 目标站 command.setAckFinish2((short) 0); // 任务完成确认位 command.setTaskNo2((short) 0); // 工作号 command.setTaskMode2(RgvTaskModeType.NONE); // 任务模式 command.setSourceStaNo2((short) 0); // 源站 command.setDestinationStaNo2((short) 0); // 目标站 command.setCommand((short) 0); return rgvControl(command)?R.ok():R.error(); } @ManagerAuth(memo = "手动复位") @PostMapping("/operator/handleReset") public R handleReset(RgvOperatorParam param) throws Exception { if (param.getRgvNo() == null) { throw new CoolException("请选择RGV"); } // 获取RGV缓存 for (RgvSlave rgv : slaveProperties.getRgv()) { // 获取RGV信息 if (param.getRgvNo().equals(rgv.getId())) { RgvThread rgvThread = (RgvThread) SlaveConnection.get(SlaveType.Rgv, rgv.getId()); if (rgvThread == null) { throw new CoolException("RGV不在线"); } RgvProtocol rgvProtocol = rgvThread.getRgvProtocol(); if (rgvProtocol == null) { throw new CoolException("RGV不在线"); } RgvCommand Command = new RgvCommand(); Command.setRgvNo(rgv.getId()); // RGV编号 Command.setTaskMode1(RgvTaskModeType.NONE); Command.setAckFinish1((short) 0); // 任务完成确认位 Command.setAckFinish2((short) 0); // 任务完成确认位 Command.setCommand((short) 0); // 任务完成确认位 // 延时发送 Thread.sleep(1000L); if (MessageQueue.offer(SlaveType.Rgv, rgv.getId(), new Task(2, Command))) { return R.ok(); } else { throw new CoolException("命令下发失败"); } } } return R.error(); } private boolean rgvControl(RgvCommand command){ if (command.getRgvNo() == null) { throw new CoolException("请选择RGV"); } for (RgvSlave rgv : slaveProperties.getRgv()) { // 获取RGV信息 if (command.getRgvNo().equals(rgv.getId())) { RgvThread rgvThread = (RgvThread) SlaveConnection.get(SlaveType.Rgv, rgv.getId()); if (rgvThread == null) { throw new CoolException("RGV不在线"); } RgvProtocol rgvProtocol = rgvThread.getRgvProtocol(); if (rgvProtocol == null) { throw new CoolException("RGV不在线"); } if (MessageQueue.offer(SlaveType.Rgv, rgv.getId(), new Task(2, command))) { return true; } else { throw new CoolException("命令下发失败"); } } } return false; } } src/main/java/com/zy/asrs/domain/enums/RgvStatusType.java
New file @@ -0,0 +1,43 @@ package com.zy.asrs.domain.enums; /** * RGV状态枚举 */ public enum RgvStatusType { // 入库 MACHINE_PAKIN("入库"), // 出库 MACHINE_PAKOUT("出库"), // 异常 MACHINE_ERROR("异常"), // 自动 MACHINE_AUTO("自动"), // 非自动/手动 MACHINE_UN_AUTO("非自动"), ; private String desc; RgvStatusType(String desc){ this.desc = desc; } public String getDesc() { return desc; } public void setDesc(String desc) { this.desc = desc; } public static RgvStatusType process(Integer ioType){ if (ioType>100) { return MACHINE_PAKOUT; } else if (ioType < 100 && ioType!=3 && ioType!=6 && ioType!=11) { return MACHINE_PAKIN; } else { return MACHINE_ERROR; } } } src/main/java/com/zy/asrs/domain/param/RgvOperatorParam.java
New file @@ -0,0 +1,25 @@ package com.zy.asrs.domain.param; import lombok.Data; /** * Created by vincent on 2020-06-02 */ @Data public class RgvOperatorParam { // RGV号 private Integer rgvNo; // 工位1源站 private Short sourceStaNo1; // 工位1目标站 private Short staNo1; // 工位2源站 private Short sourceStaNo2; // 工位2目标站 private Short staNo2; } src/main/java/com/zy/asrs/domain/vo/RgvMsgTableVo.java
New file @@ -0,0 +1,62 @@ package com.zy.asrs.domain.vo; import com.zy.asrs.utils.Utils; import lombok.Data; /** * Created by vincent on 2020-06-02 */ @Data public class RgvMsgTableVo { // RGV号 private Integer rgvNo; // 工作号 private Short workNo1 = 0; // 状态 private String status = "-"; // 源站 private String sourceStaNo = "-"; // 目标站 private String staNo = "-"; // 源库位 private String sourceLocNo = "-"; // 目标库位 private String locNo = "-"; // 异常 private String error = ""; // 原点 private String origin = ""; // 命令 private String command = ""; // 走行速度(m/min) private Float xspeed = 0.0F; // 走行距离(Km) private Float xdistance = 0.0F; // 走行时长(H) private Float xduration = 0.0F; public void setXspeed(Float xspeed) { this.xspeed = Utils.scale(xspeed); } public void setXdistance(Float xdistance) { this.xdistance = Utils.scale(xdistance); } public void setXduration(Float xduration) { this.xduration = Utils.scale(xduration); } } src/main/java/com/zy/asrs/domain/vo/RgvStateTableVo.java
New file @@ -0,0 +1,50 @@ package com.zy.asrs.domain.vo; import lombok.Data; /** * Created by vincent on 2020-06-02 */ @Data public class RgvStateTableVo { // RGV号 private Integer RgvNo; // 模式 private String statusType = "-"; // 状态 private String status = "-"; // 任务号 private Short workNo1 = 0; // 状态 private String status1 = "-"; // 有物 private String loading1 = "-"; // RGV位置 private Short RgvPos = 0; // 走行定位 private String walkPos = "-"; // 任务号 private Short workNo2 = 0; // 状态 private String status2 = "-"; // 有物 private String loading2 = "-"; //异常 private String warnCode; // 异常码描述 private String alarm = "-"; } src/main/java/com/zy/asrs/entity/BasRgvErr.java
New file @@ -0,0 +1,127 @@ package com.zy.asrs.entity; import com.core.common.Cools;import com.baomidou.mybatisplus.annotations.TableId; import com.baomidou.mybatisplus.enums.IdType; import com.baomidou.mybatisplus.annotations.TableField; import com.core.common.SpringUtils; import com.zy.system.service.UserService; import com.zy.system.entity.User; import java.text.SimpleDateFormat; import java.util.Date; import org.springframework.format.annotation.DateTimeFormat; import com.core.common.SpringUtils; import com.zy.system.service.UserService; import com.zy.system.entity.User; import java.text.SimpleDateFormat; import java.util.Date; import io.swagger.annotations.ApiModelProperty; import lombok.Data; import com.baomidou.mybatisplus.annotations.TableName; import java.io.Serializable; @Data @TableName("asr_bas_rgv_err") public class BasRgvErr implements Serializable { private static final long serialVersionUID = 1L; /** * 异常码 */ @ApiModelProperty(value= "异常码") @TableId(value = "error_code", type = IdType.INPUT) @TableField("error_code") private Long errorCode; /** * 异常 */ @ApiModelProperty(value= "异常") @TableField("err_name") private String errName; /** * 修改人员 */ @ApiModelProperty(value= "修改人员") @TableField("modi_user") private Long modiUser; /** * 修改时间 */ @ApiModelProperty(value= "修改时间") @TableField("modi_time") @DateTimeFormat(pattern="yyyy-MM-dd HH:mm:ss") private Date modiTime; /** * 添加人员 */ @ApiModelProperty(value= "添加人员") @TableField("appe_user") private Long appeUser; /** * 添加时间 */ @ApiModelProperty(value= "添加时间") @TableField("appe_time") @DateTimeFormat(pattern="yyyy-MM-dd HH:mm:ss") private Date appeTime; public BasRgvErr() {} public BasRgvErr(Long errorCode,String errName,Long modiUser,Date modiTime,Long appeUser,Date appeTime) { this.errorCode = errorCode; this.errName = errName; this.modiUser = modiUser; this.modiTime = modiTime; this.appeUser = appeUser; this.appeTime = appeTime; } // BasRgvErr basRgvErr = new BasRgvErr( // null, // 异常码[非空] // null, // 异常 // null, // 修改人员 // null, // 修改时间 // null, // 添加人员 // null // 添加时间 // ); public String getModiUser$(){ UserService service = SpringUtils.getBean(UserService.class); User user = service.selectById(this.modiUser); if (!Cools.isEmpty(user)){ return String.valueOf(user.getNickname()); } return null; } public String getModiTime$(){ if (Cools.isEmpty(this.modiTime)){ return ""; } return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(this.modiTime); } public String getAppeUser$(){ UserService service = SpringUtils.getBean(UserService.class); User user = service.selectById(this.appeUser); if (!Cools.isEmpty(user)){ return String.valueOf(user.getNickname()); } return null; } public String getAppeTime$(){ if (Cools.isEmpty(this.appeTime)){ return ""; } return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(this.appeTime); } } src/main/java/com/zy/asrs/mapper/BasRgvErrMapper.java
New file @@ -0,0 +1,12 @@ package com.zy.asrs.mapper; import com.zy.asrs.entity.BasRgvErr; import com.baomidou.mybatisplus.mapper.BaseMapper; import org.apache.ibatis.annotations.Mapper; import org.springframework.stereotype.Repository; @Mapper @Repository public interface BasRgvErrMapper extends BaseMapper<BasRgvErr> { } src/main/java/com/zy/asrs/service/BasRgvErrService.java
New file @@ -0,0 +1,8 @@ package com.zy.asrs.service; import com.zy.asrs.entity.BasRgvErr; import com.baomidou.mybatisplus.service.IService; public interface BasRgvErrService extends IService<BasRgvErr> { } src/main/java/com/zy/asrs/service/impl/BasRgvErrServiceImpl.java
New file @@ -0,0 +1,12 @@ package com.zy.asrs.service.impl; import com.zy.asrs.mapper.BasRgvErrMapper; import com.zy.asrs.entity.BasRgvErr; import com.zy.asrs.service.BasRgvErrService; import com.baomidou.mybatisplus.service.impl.ServiceImpl; import org.springframework.stereotype.Service; @Service("basRgvErrService") public class BasRgvErrServiceImpl extends ServiceImpl<BasRgvErrMapper, BasRgvErr> implements BasRgvErrService { } src/main/java/com/zy/common/CodeBuilder.java
@@ -20,7 +20,7 @@ generator.url="localhost:1433;databasename=xjhsasrs"; generator.username="sa"; generator.password="sa@123"; generator.table="asr_bas_rgv_opt"; generator.table="asr_bas_rgv_err"; generator.packagePath="com.zy.asrs"; generator.controller = false; src/main/java/com/zy/core/enums/RgvTaskModeType.java
@@ -5,7 +5,7 @@ NONE(0), // 无 FETCH(1), // 取货 PUT(2), // 放货 FETCH_PUT(3), // 库位移转 FETCH_PUT(3), // 取放货 // X_MOVE(4), // 站位移转 // Y_MOVE(5), // 站位移转 // XY_MOVE(6), // 站位移转 src/main/resources/mapper/BasRgvErrMapper.xml
New file @@ -0,0 +1,16 @@ <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <mapper namespace="com.zy.asrs.mapper.BasRgvErrMapper"> <!-- 通用查询映射结果 --> <resultMap id="BaseResultMap" type="com.zy.asrs.entity.BasRgvErr"> <result column="error_code" property="errorCode" /> <result column="err_name" property="errName" /> <result column="modi_user" property="modiUser" /> <result column="modi_time" property="modiTime" /> <result column="appe_user" property="appeUser" /> <result column="appe_time" property="appeTime" /> </resultMap> </mapper> src/main/webapp/views/index.html
@@ -17,6 +17,7 @@ <li><a id="console" onclick="nav(this.id)" class="nav-select" href="#">主控图</a></li> <li><a id="pipeline" onclick="nav(this.id)" class="nav-unselect" href="#">输送设备</a></li> <li><a id="crn" onclick="nav(this.id)" class="nav-unselect" href="#">堆垛机</a></li> <li><a id="rgv" onclick="nav(this.id)" class="nav-unselect" href="#">RGV</a></li> </ul> </div> </div> src/main/webapp/views/rgv.html
New file @@ -0,0 +1,644 @@ <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>堆垛机监控管理</title> <meta name="renderer" content="webkit"> <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1"> <meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=0"> <link rel="stylesheet" type="text/css" href="../static/css/normalize.css"> <link rel="stylesheet" type="text/css" href="../static/css/common.css"> <link rel="stylesheet" type="text/css" href="../static/css/crn.css"> <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/js/layer/layer.js"></script> <style> .demoBtn { vertical-align: middle; width: 20%; height: 25px; left: 0; top: 0; text-shadow: inherit; font-size: 15px; margin-left: 5px; margin-right: 5px; display: inline-block; background-color: #FF5722; border: none; color: #FFF; box-shadow: 1px 1px 5px #B6B6B6; border-radius: 3px; cursor: pointer; } .demoBtn:hover { opacity: 0.8 } .demoBtn:focus { outline: 0; } </style> </head> <body> <div style="padding: 10px;height: 100%;float: left;width: 6%"> <div class="button-window"></div> </div> <div style="height: 100%;padding-left: 6%"> <div style="padding: 10px;height: 100%"> <!-- 日志监控板 --> <div class="log-board"> <!-- 执行命令 --> <!-- 执行命令 --> <div class="command-log"> <h3>执行中的命令</h3> <div class="crn-command-item"> <label>1#</label> <button id="demoBtn-1" class="demoBtn" onclick="demoSwitch(this.id)"> - </button> <!-- <span> </span>--> <input id="crn1" disabled="disabled"> </div> <div class="crn-command-item"> <label>2#</label> <button id="demoBtn-2" class="demoBtn" onclick="demoSwitch(this.id)"> - </button> <!-- <span> </span>--> <input id="crn2" disabled="disabled"> </div> <div class="crn-command-item"> <label>3#</label> <button id="demoBtn-3" class="demoBtn" onclick="demoSwitch(this.id)"> - </button> <!-- <span> </span>--> <input id="crn3" disabled="disabled"> </div> <div class="crn-command-item"> <label>4#</label> <button id="demoBtn-4" class="demoBtn" onclick="demoSwitch(this.id)"> - </button> <!-- <span> </span>--> <input id="crn4" disabled="disabled"> </div> <div class="crn-command-item"> <label>5#</label> <button id="demoBtn-5" class="demoBtn" onclick="demoSwitch(this.id)"> - </button> <!-- <span> </span>--> <input id="crn5" disabled="disabled"> </div> </div> <!-- 堆垛机状态位信息 --> <div class="crn-state"> <table id="crn-state-table"> <thead> <tr> <th>堆垛机</th> <th>模式</th> <th>状态</th> <th>有物</th> <th>列</th> <th>层</th> <th>货叉定位</th> <th>载货台定位</th> <th>走行在定位</th> <th>故障代码</th> <th>故障描述</th> </tr> </thead> <tbody> </tbody> </table> </div> </div> <!-- 堆垛机状态 --> <div class="crn-msg"> <table id="crn-msg-table"> <thead> <tr> <th>堆垛机</th> <th>工作号</th> <th>状态</th> <th>源站</th> <th>目标站</th> <th>源库位</th> <th>目标库位</th> <!-- <th>走行速度(m/min)</th>--> <!-- <th>升降速度(m/min)</th>--> <!-- <th>叉牙速度(m/min)</th>--> <!-- <th>走行距离(Km)</th>--> <!-- <th>升降距离(Km)</th>--> <!-- <th>走行时长(H)</th>--> <!-- <th>升降时长(H)</th>--> </tr> </thead> <tbody> </tbody> </table> </div> <!-- 手动操作 --> <div class="crn-operation"> <!-- 遮罩层 --> <div class="crn-operation-shade"> <span class="crn-operation-shade-span"> WCS 系统运行中,请停止后操作 </span> </div> <!-- 设备任务选择 --> <div class="task-select"> <!-- 堆垛机选择 --> <div id="crn-select" class="operator-item" style="width: 55%"> <span class="select-title">堆垛机号</span> <div class="select-container" style="padding: 20px 0;"> <label><input type="radio" name="crnSelect" value="1" checked> 1号堆垛机</label> <label><input type="radio" name="crnSelect" value="2"> 2号堆垛机</label> <label><input type="radio" name="crnSelect" value="3"> 3号堆垛机</label> <label><input type="radio" name="crnSelect" value="4"> 4号堆垛机</label> <label><input type="radio" name="crnSelect" value="5"> 5号堆垛机</label> </div> </div> <!-- 源站/源库位 选择 --> <div id="source-select" class="operator-item"> <span class="select-title">源站/源库位</span> <div class="select-container"> <div class="select-container-item"> <span>站</span> <label><input id="sourceStaNo" type="number" name="points" min="0" /></label> </div> <div class="select-container-item"> <span>排</span> <label><input id="sourceRow" type="number" name="points" min="1" style="background-color: #a9eeff" value="1" /></label> </div> <div class="select-container-item"> <span>列</span> <label><input id="sourceBay" type="number" name="points" min="0" style="background-color: #a9eeff" value="0" /></label> </div> <div class="select-container-item"> <span>层</span> <label><input id="sourceLev" type="number" name="points" min="1" style="background-color: #a9eeff" value="1" /></label> </div> </div> </div> <!-- 目标站/目标库位 选择 --> <div id="target-select" class="operator-item"> <span class="select-title">目标站/目标库位</span> <div class="select-container"> <div class="select-container-item"> <span>站</span> <label><input id="staNo" type="number" name="points" min="0" /></label> </div> <div class="select-container-item"> <span>排</span> <label><input id="row" type="number" name="points" min="1" style="background-color: #a9eeff" value="1" /></label> </div> <div class="select-container-item"> <span>列</span> <label><input id="bay" type="number" name="points" min="0" style="background-color: #a9eeff" value="0" /></label> </div> <div class="select-container-item"> <span>层</span> <label><input id="lev" type="number" name="points" min="1" style="background-color: #a9eeff" value="1" /></label> </div> </div> </div> </div> <!-- 设备任务操作 --> <div class="task-operator"> <fieldset> <legend>手动操作</legend> <div class="button-group"> <button class="item" onclick="put()">入库</button> <button class="item" onclick="take()">出库</button> <button class="item" onclick="stockMove()">库位转移</button> <button class="item" onclick="siteMove()">站到站</button> <!-- <button class="item" onclick="bacOrigin()">回原点</button>--> <!-- <button class="item" onclick="reverseOrigin()">反原点</button>--> <!-- <button class="item" onclick="coorMove()">坐标移行</button>--> <button class="item" onclick="taskComplete()">任务完成</button> <!-- <button class="item" onclick="pause()">暂停</button>--> <!-- <button class="item" onclick="boot()">启动</button>--> <button class="item" onclick="clearCommand()">清除命令</button> <button class="item" onclick="handleReset()">复位</button> </div> </fieldset> </div> </div> <!-- 堆垛机日志输出 --> <div class="crn-output-board"> <textarea id="crn-output"></textarea> </div> </div> </div> </body> <script> // 空白行数 var crnStateTableBlankRows = 0; var crnMsgTableBlankRows = 0; // 实际行数 var crnStateTableFullRows = 0; var crnMsgTableFullRows = 0; // 初始化 var crnOutputDom = document.getElementById("crn-output"); $(document).ready(function() { getCommandLog(); initCrnStateTable(); getCrnStateInfo(); initCrnMsgTable(); getCrnMsgInfo(); operatorBlockShow(); }); // 数据更新 setInterval(function () { getCrnStateInfo(); getCrnMsgInfo(); getCommandLog(); },1000); setInterval(function () { getCrnOutput(); operatorBlockShow(); initDemo(); },500); // 判断手动操作模块是否可用 function operatorBlockShow() { if (parent.systemRunning) { $('.crn-operation').css("opacity", "0.5"); $('.crn-operation-shade').show(); $('.crn-operation-shade-span').show(); } else { $('.crn-operation').css("opacity", "1"); $('.crn-operation-shade').hide(); $('.crn-operation-shade-span').hide(); } } // 获取堆垛机执行中的命令 function getCommandLog() { $.ajax({ url: baseUrl + "/crn/command/ongoing", headers: {'token': localStorage.getItem('token')}, method: 'POST', success: function (res) { if (res.code === 200) { var commands = res.data; for (var i=0; i<commands.length;i++){ $("#crn"+commands[i].crnNo).val(commands[i].command); } } else if (res.code === 403) { window.location.href = baseUrl + "/login"; } else { console.log(res.msg); } } }) } // 堆垛机信息表获取 ---- 表一 function getCrnStateInfo() { var tableEl = $('#crn-state-table'); $.ajax({ url: baseUrl+ "/crn/table/crn/state", headers: {'token': localStorage.getItem('token')}, method: 'POST', success: function (res) { if (res.code === 200){ var table = res.data; if (table.length > crnStateTableBlankRows && table.length !== crnStateTableFullRows) { initCrnStateTable(table.length-crnStateTableBlankRows); crnStateTableFullRows = table.length; } for (var i=1;i<=table.length;i++){ var tr = tableEl.find("tr").eq(i); setVal(tr.children("td").eq(0), table[i-1].crnNo); setVal(tr.children("td").eq(1), table[i-1].statusType); setVal(tr.children("td").eq(2), table[i-1].status); setVal(tr.children("td").eq(3), table[i-1].loading); setVal(tr.children("td").eq(4), table[i-1].bay); setVal(tr.children("td").eq(5), table[i-1].lev); setVal(tr.children("td").eq(6), table[i-1].forkOffset); setVal(tr.children("td").eq(7), table[i-1].liftPos); setVal(tr.children("td").eq(8), table[i-1].walkPos); setVal(tr.children("td").eq(9), table[i-1].warnCode); setVal(tr.children("td").eq(10), table[i-1].alarm); } } else if (res.code === 403){ window.location.href = baseUrl+"/login"; } else { console.log(res.msg); } } }); } // 堆垛机数据表获取 ---- 表二 function getCrnMsgInfo() { var tableEl = $('#crn-msg-table'); $.ajax({ url: baseUrl+ "/crn/table/crn/msg", headers: {'token': localStorage.getItem('token')}, method: 'POST', success: function (res) { if (res.code === 200){ var table = res.data; if (table.length > crnStateTableBlankRows && table.length !== crnMsgTableFullRows) { initCrnStateTable(table.length-crnStateTableBlankRows); crnMsgTableFullRows = table.length; } for (var i=1;i<=table.length;i++){ var tr = tableEl.find("tr").eq(i); setVal(tr.children("td").eq(0), table[i-1].crnNo); setVal(tr.children("td").eq(1), table[i-1].workNo); setVal(tr.children("td").eq(2), table[i-1].status); setVal(tr.children("td").eq(3), table[i-1].sourceStaNo); setVal(tr.children("td").eq(4), table[i-1].staNo); setVal(tr.children("td").eq(5), table[i-1].sourceLocNo); setVal(tr.children("td").eq(6), table[i-1].locNo); // setVal(tr.children("td").eq(7), table[i-1].xspeed); // setVal(tr.children("td").eq(8), table[i-1].yspeed); // setVal(tr.children("td").eq(9), table[i-1].zspeed); // setVal(tr.children("td").eq(10), table[i-1].xdistance); // setVal(tr.children("td").eq(11), table[i-1].ydistance); // setVal(tr.children("td").eq(12), table[i-1].xduration); // setVal(tr.children("td").eq(13), table[i-1].yduration); } } else if (res.code === 403){ window.location.href = baseUrl+"/login"; } else { console.log(res.msg); } } }); } // 堆垛机手动操作区 ----------------------------------------------------------------------- function getReqParam() { var crnNo = $('input[name="crnSelect"]:checked').val(); var sourceStaNo = $('#sourceStaNo').val(); var sourceRow = $('#sourceRow').val(); var sourceBay = $('#sourceBay').val(); var sourceLev = $('#sourceLev').val(); var staNo = $('#staNo').val(); var row = $('#row').val(); var bay = $('#bay').val(); var lev = $('#lev').val(); return { crnNo: crnNo, sourceStaNo: sourceStaNo, sourceRow: sourceRow, sourceBay: sourceBay, sourceLev: sourceLev, staNo: staNo, row: row, bay: bay, lev: lev }; } // 入库 function put() { http.post(baseUrl+"/crn/operator/put", getReqParam(), function (res) { layer.msg(res.msg); }); } // 出库 function take() { http.post(baseUrl+"/crn/operator/take", getReqParam(), function (res) { layer.msg(res.msg); }); } // 库位转移 function stockMove() { http.post(baseUrl+"/crn/operator/stockMove", getReqParam(), function (res) { layer.msg(res.msg); }); } // 站到站 function siteMove() { http.post(baseUrl+"/crn/operator/siteMove", getReqParam(), function (res) { layer.msg(res.msg); }); } // 坐标移动 function coorMove() { http.post(baseUrl+"/crn/operator/coorMove", getReqParam(), function (res) { layer.msg(res.msg); }); } // 回原点 function bacOrigin() { http.post(baseUrl+"/crn/operator/bacOrigin", getReqParam(), function (res) { layer.msg(res.msg); }); } // 回原点 function reverseOrigin() { http.post(baseUrl+"/crn/operator/reverseOrigin", getReqParam(), function (res) { layer.msg(res.msg); }); } // 任务完成 function taskComplete() { http.post(baseUrl+"/crn/operator/taskComplete", getReqParam(), function (res) { layer.msg(res.msg); }); } // 暂停 function pause() { http.post(baseUrl+"/crn/operator/pause", getReqParam(), function (res) { layer.msg(res.msg); }); } // 启动 function boot() { http.post(baseUrl+"/crn/operator/boot", getReqParam(), function (res) { layer.msg(res.msg); }); } // 清除命令 function clearCommand() { http.post(baseUrl+"/crn/operator/clearCommand", getReqParam(), function (res) { layer.msg(res.msg); }); } // 手动复位 function handleReset() { http.post(baseUrl+"/crn/operator/handleReset", getReqParam(), function (res) { layer.msg(res.msg); }); } // 输送设备日志输出 ----------------------------------------------------------------------- function getCrnOutput() { $.ajax({ url: baseUrl + "/crn/output/site", headers: {'token': localStorage.getItem('token')}, method: 'POST', success: function (res) { console.log(res) if (res.code === 200) { crnOutput(res.data); } else if (res.code === 403) { window.location.href = baseUrl + "/login"; } else { console.log(res.msg); } } }) } // ------------------------------------------------------------------------------------------------ // 堆垛机信息表获取 ----- 表一 function initCrnStateTable(row) { var line; if (row === undefined){ var one = $('#crn-state-table thead').height(); var total = $('.crn-state').height(); var count = total / one; count = parseInt(count) - 1; crnStateTableBlankRows = count; line = count; } else { line = row; } var html = ""; for (var i = 0; i < line; i ++){ html += " <tr>\n" + " <td></td>\n" + " <td></td>\n" + " <td></td>\n" + " <td></td>\n" + " <td></td>\n" + " <td></td>\n" + " <td></td>\n" + " <td></td>\n" + " <td></td>\n" + " <td></td>\n" + " <td></td>\n" + " </tr>\n"; } $('#crn-state-table tbody').after(html); } // 堆垛机数据表获取 ----- 表二 function initCrnMsgTable(row) { var line; if (row === undefined){ var one = $('#crn-msg-table thead').height(); var total = $('.crn-msg').height(); var count = total / one; count = parseInt(count) - 1; crnMsgTableBlankRows = count; line = count; } else { line = row; } var html = ""; for (var i = 0; i < line; i ++){ html += " <tr>\n" + " <td></td>\n" + " <td></td>\n" + " <td></td>\n" + " <td></td>\n" + " <td></td>\n" + " <td></td>\n" + " <td></td>\n" + " <td></td>\n" + " <td></td>\n" + " <td></td>\n" + " <td></td>\n" + " <td></td>\n" + " <td></td>\n" + " <td></td>\n" + " </tr>\n"; } $('#crn-msg-table tbody').after(html); } // 日志输出框 function crnOutput(content){ crnOutputDom.value += content; crnOutputDom.scrollTop = crnOutputDom.scrollHeight; } var crnDemoData; function initDemo() { $.ajax({ url: baseUrl+"/crn/demo/status", async: false, method: 'GET', success: function (res) { if (res.code === 200) { crnDemoData = res.data; crnDemoData.forEach(function (e) { $("#demoBtn-"+e.crnNo).html(e.demo?'停止':'演示'); }) } else if (res.code === 403){ parent.location.href = baseUrl+"/login"; } else { layer.msg(res.msg, {icon: 2}); } } }) } function demoSwitch(el) { var crnId = el.split("-")[1]; var opt; if (crnDemoData == null) { initDemo(); } for (var i = 0; i<crnDemoData.length; i++) { if (Number(crnDemoData[i].crnNo) === Number(crnId)) { opt = !crnDemoData[i].demo; } } layer.confirm(crnId + ' 号堆垛机确定'+ (opt?'开始':'停止') + '演示吗?', function(){ doDemo(crnId, 'root', opt); // 停止wcs系统 }); } function doDemo(crnId, password, opt) { // 加载tips var index = layer.load(1, { shade: [0.1,'#fff'] }); $.ajax({ url: baseUrl+ "/crn/demo/switch", headers: {'token': localStorage.getItem('token')}, // async: false, data: { crnId: Number(crnId), password: password, opt: opt }, method: 'POST', success: function (res) { layer.close(index); if (res.code === 200){ layer.msg(res.msg, {icon: 1}); } else if (res.code === 403){ window.location.href = baseUrl+"/login"; } else { layer.msg(res.msg, {icon: 2}); } } }); } </script> </html>