zy-asrs-wcs/src/main/java/com/zy/asrs/wcs/core/action/LiftAction.java
@@ -41,7 +41,7 @@ redisCommand.setAssignCommand(assignCommand);//命令 //任务数据保存到redis if (redisUtil.set(DeviceRedisConstant.LIFT_WORK_FLAG + assignCommand.getTaskNo(), JSON.toJSONString(redisCommand))) { liftProtocol.setTaskNo(assignCommand.getTaskNo()); liftThread.setSyncTaskNo(assignCommand.getTaskNo()); return true; } return false; zy-asrs-wcs/src/main/java/com/zy/asrs/wcs/core/controller/BasLiftController.java
@@ -1,25 +1,44 @@ package com.zy.asrs.wcs.system.controller; package com.zy.asrs.wcs.core.controller; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.zy.asrs.framework.common.Cools; import com.zy.asrs.framework.common.R; import com.zy.asrs.framework.common.SnowflakeIdWorker; import com.zy.asrs.wcs.common.annotation.OperationLog; import com.zy.asrs.wcs.common.domain.BaseParam; import com.zy.asrs.wcs.common.domain.KeyValVo; import com.zy.asrs.wcs.common.domain.PageParam; import com.zy.asrs.wcs.core.domain.param.LiftOperatorParam; import com.zy.asrs.wcs.core.entity.BasLift; import com.zy.asrs.wcs.core.entity.Motion; import com.zy.asrs.wcs.core.entity.Task; import com.zy.asrs.wcs.core.entity.TaskCtg; import com.zy.asrs.wcs.core.kernel.AnalyzeService; import com.zy.asrs.wcs.core.model.enums.DeviceCtgType; import com.zy.asrs.wcs.core.model.enums.TaskStsType; import com.zy.asrs.wcs.core.service.BasLiftService; import com.zy.asrs.wcs.core.service.MotionService; import com.zy.asrs.wcs.core.service.TaskCtgService; import com.zy.asrs.wcs.core.service.TaskService; import com.zy.asrs.wcs.core.utils.Utils; import com.zy.asrs.wcs.rcs.News; import com.zy.asrs.wcs.rcs.cache.SlaveConnection; import com.zy.asrs.wcs.rcs.entity.Device; import com.zy.asrs.wcs.rcs.model.enums.LiftProtocolStatusType; import com.zy.asrs.wcs.rcs.model.enums.SlaveType; import com.zy.asrs.wcs.rcs.service.DeviceService; import com.zy.asrs.wcs.rcs.thread.LiftThread; import com.zy.asrs.wcs.system.controller.BaseController; import com.zy.asrs.wcs.system.entity.Dict; import com.zy.asrs.wcs.system.service.DictService; import com.zy.asrs.wcs.utils.ExcelUtil; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.web.bind.annotation.*; import javax.servlet.http.HttpServletResponse; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.Map; import java.util.*; @RestController @RequestMapping("/api") @@ -27,6 +46,20 @@ @Autowired private BasLiftService basLiftService; @Autowired private TaskCtgService taskCtgService; @Autowired private DeviceService deviceService; @Autowired private SnowflakeIdWorker snowflakeIdWorker; @Autowired private TaskService taskService; @Autowired private AnalyzeService analyzeService; @Autowired private MotionService motionService; @Autowired private DictService dictService; @PreAuthorize("hasAuthority('core:basLift:list')") @PostMapping("/basLift/page") @@ -98,4 +131,89 @@ ExcelUtil.build(ExcelUtil.create(basLiftService.list(), BasLift.class), response); } //获取楼层 @PreAuthorize("hasAuthority('core:basLift:list')") @PostMapping("/basLift/getMapLev") public R getMapLev() { List<Dict> dicts = dictService.list(new LambdaQueryWrapper<Dict>() .like(Dict::getFlag, "map") .eq(Dict::getStatus, 1)); return R.ok().add(dicts.size()); } @PreAuthorize("hasAuthority('core:basLift:operator')") @PostMapping("/basLift/operator/lift") public R liftOperator(@RequestBody LiftOperatorParam param) { if (Cools.isEmpty(param.getLiftNo())) { return R.error("参数为空"); } Integer liftNo = param.getLiftNo(); //获取手动任务类型 TaskCtg taskCtg = taskCtgService.getOne(new LambdaQueryWrapper<TaskCtg>() .eq(TaskCtg::getFlag, "MANUAL") .eq(TaskCtg::getStatus, 1)); if (taskCtg == null) { return R.error(); } Device device = deviceService.getOne(new LambdaQueryWrapper<Device>() .eq(Device::getDeviceType, DeviceCtgType.LIFT.val()) .eq(Device::getStatus, 1) .eq(Device::getDeviceNo, liftNo)); if (device == null) { return R.error("设备不存在"); } LiftThread liftThread = (LiftThread) SlaveConnection.get(SlaveType.Lift, device.getId().intValue()); if (liftThread == null) { return R.error("设备离线"); } if (param.getLiftTaskMode().equals("reset")) { //提升机复位 liftThread.setSyncTaskNo(0); liftThread.setProtocolStatus(LiftProtocolStatusType.IDLE); return R.ok("复位成功"); } Task task = new Task(); task.setUuid(String.valueOf(snowflakeIdWorker.nextId())); task.setTaskNo(String.valueOf(Utils.getTaskNo("MANUAL"))); task.setTaskSts(TaskStsType.NEW_MANUAL.sts); task.setTaskCtg(taskCtg.getId()); task.setPriority(10); task.setOriginSite(null); task.setOriginLoc(param.getSourceStaNo()); task.setDestSite(param.getLiftTaskMode()); task.setDestLoc(param.getStaNo()); task.setIoTime(new Date()); task.setStartTime(new Date()); task.setStatus(1); task.setMemo("manual"); task.setLiftNo(liftNo); boolean result = taskService.save(task); if (!result) { return R.error(); } task = taskService.getById(task.getId()); // generate motion list List<Motion> motionList = analyzeService.generateLiftManualMotion(task); if (Cools.isEmpty(motionList)) { News.error("保存{}提升机手动任务失败!!!", liftNo); return R.error(); } motionService.batchInsert(motionList, task.getUuid(), Integer.valueOf(task.getTaskNo())); task.setTaskSts(TaskStsType.ANALYZE_MANUAL.sts); if (!taskService.updateById(task)) { News.error("保存{}提升机手动任务失败!!!", liftNo); return R.error(); } return R.ok(); } } zy-asrs-wcs/src/main/java/com/zy/asrs/wcs/core/controller/BasShuttleController.java
@@ -2,7 +2,6 @@ import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.zy.asrs.framework.common.BaseRes; import com.zy.asrs.framework.common.Cools; import com.zy.asrs.framework.common.R; import com.zy.asrs.framework.common.SnowflakeIdWorker; @@ -27,7 +26,6 @@ import com.zy.asrs.wcs.rcs.News; import com.zy.asrs.wcs.rcs.cache.SlaveConnection; import com.zy.asrs.wcs.rcs.entity.Device; import com.zy.asrs.wcs.rcs.entity.DeviceType; import com.zy.asrs.wcs.rcs.model.enums.SlaveType; import com.zy.asrs.wcs.rcs.model.protocol.ShuttleProtocol; import com.zy.asrs.wcs.rcs.service.DeviceService; @@ -142,7 +140,7 @@ Integer shuttleNo = param.getShuttleNo(); //获取迁移任务类型 //获取手动任务类型 TaskCtg taskCtg = taskCtgService.getOne(new LambdaQueryWrapper<TaskCtg>() .eq(TaskCtg::getFlag, "MANUAL") .eq(TaskCtg::getStatus, 1)); zy-asrs-wcs/src/main/java/com/zy/asrs/wcs/core/domain/param/LiftOperatorParam.java
New file @@ -0,0 +1,20 @@ package com.zy.asrs.wcs.core.domain.param; import lombok.Data; @Data public class LiftOperatorParam { // 提升机号 private Integer liftNo; //操作模式 private String liftTaskMode; //源站 private String sourceStaNo; //目标站 private String staNo; } zy-asrs-wcs/src/main/java/com/zy/asrs/wcs/core/kernel/AnalyzeService.java
@@ -2,6 +2,7 @@ import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.zy.asrs.framework.common.Cools; import com.zy.asrs.framework.common.R; import com.zy.asrs.wcs.core.domain.dto.MotionDto; import com.zy.asrs.wcs.core.entity.ShuttleStandby; import com.zy.asrs.wcs.core.entity.Task; @@ -18,6 +19,7 @@ import com.zy.asrs.wcs.rcs.cache.SlaveConnection; import com.zy.asrs.wcs.core.entity.Motion; import com.zy.asrs.wcs.rcs.entity.Device; import com.zy.asrs.wcs.rcs.model.enums.LiftProtocolStatusType; import com.zy.asrs.wcs.rcs.model.enums.SlaveType; import com.zy.asrs.wcs.rcs.model.protocol.LiftProtocol; import com.zy.asrs.wcs.rcs.model.protocol.ShuttleProtocol; @@ -1146,4 +1148,41 @@ return motionList; } /** * 生成提升机手动动作 */ public List<Motion> generateLiftManualMotion(Task task) { List<Motion> motionList = new ArrayList<>(); if (task.getTaskSts() != TaskStsType.NEW_MANUAL.sts) { return motionList; } Device device = deviceService.getOne(new LambdaQueryWrapper<Device>() .eq(Device::getDeviceNo, task.getLiftNo()) .eq(Device::getDeviceType, DeviceCtgType.LIFT.val()) .eq(Device::getHostId, task.getHostId()) .eq(Device::getStatus, 1)); if (device == null) { return motionList; } if (task.getDestSite().equals("move")) { //提升机升降楼层 // 提升机空载移动到穿梭车层 motionList.addAll(kernelService.liftMove( null , MotionDto.build((dto -> { dto.setLiftNo(device.getId().intValue()); dto.setLev(Integer.parseInt(task.getDestLoc())); })) )); } else if (task.getDestSite().equals("movePallet")) { //移动托盘 } return motionList; } } zy-asrs-wcs/src/main/java/com/zy/asrs/wcs/core/kernel/command/LiftCommandService.java
@@ -70,7 +70,7 @@ case LIFT_MOVE: // 如果已经在目标层,那边层过滤 if (liftProtocol.getLev().equals(Integer.valueOf(motion.getTarget()))) { liftProtocol.setTaskNo(motion.getTaskNo()); liftThread.setSyncTaskNo(motion.getTaskNo()); break; } @@ -338,7 +338,7 @@ return false; } liftProtocol.setTaskNo(0);//清零工作号 liftThread.setSyncTaskNo(0);//清零工作号 return true; } zy-asrs-wcs/src/main/java/com/zy/asrs/wcs/rcs/model/protocol/LiftProtocol.java
@@ -144,6 +144,30 @@ */ private Object extend; public String getRun$() { if (this.run == null) { return "未知"; } return this.run ? "运行中" : "空闲"; } public String getReady$() { if (this.ready == null) { return "未知"; } return this.ready ? "就绪" : "未就绪"; } public String getModel$() { if (this.model == null) { return "未知"; } return this.model ? "自动" : "手动"; } /** * 设置提升机状态 */ zy-asrs-wcs/src/main/java/com/zy/asrs/wcs/rcs/service/LiftService.java
New file @@ -0,0 +1,11 @@ package com.zy.asrs.wcs.rcs.service; import com.zy.asrs.wcs.rcs.model.protocol.LiftProtocol; import java.util.List; public interface LiftService { List<LiftProtocol> getLiftStatusList(Long hostId); } zy-asrs-wcs/src/main/java/com/zy/asrs/wcs/rcs/service/impl/LiftServiceImpl.java
New file @@ -0,0 +1,41 @@ package com.zy.asrs.wcs.rcs.service.impl; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.zy.asrs.wcs.core.model.enums.DeviceCtgType; import com.zy.asrs.wcs.rcs.cache.SlaveConnection; import com.zy.asrs.wcs.rcs.entity.Device; import com.zy.asrs.wcs.rcs.model.enums.SlaveType; import com.zy.asrs.wcs.rcs.model.protocol.LiftProtocol; import com.zy.asrs.wcs.rcs.service.DeviceService; import com.zy.asrs.wcs.rcs.service.LiftService; import com.zy.asrs.wcs.rcs.thread.LiftThread; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import java.util.ArrayList; import java.util.List; @Service("LiftService") public class LiftServiceImpl implements LiftService { @Autowired private DeviceService deviceService; @Override public List<LiftProtocol> getLiftStatusList(Long hostId) { ArrayList<LiftProtocol> data = new ArrayList<>(); List<Device> list = deviceService.list(new LambdaQueryWrapper<Device>() .eq(Device::getHostId, hostId) .eq(Device::getStatus, 1) .eq(Device::getDeviceType, DeviceCtgType.LIFT.val())); for (Device device : list) { LiftThread liftThread = (LiftThread) SlaveConnection.get(SlaveType.Lift, device.getId().intValue()); if (liftThread == null) { continue; } LiftProtocol status = liftThread.getStatus(); data.add(status); } return data; } } zy-asrs-wcs/src/main/java/com/zy/asrs/wcs/rcs/service/impl/ShuttleServiceImpl.java
@@ -26,7 +26,6 @@ @Override public List<ShuttleProtocol> getShuttleStatusList(Long hostId) { ArrayList<ShuttleProtocol> data = new ArrayList<>(); List<Device> list = deviceService.list(new LambdaQueryWrapper<Device>() .eq(Device::getHostId, hostId) @@ -34,6 +33,9 @@ .eq(Device::getDeviceType, DeviceCtgType.SHUTTLE.val())); for (Device device : list) { ShuttleThread shuttleThread = (ShuttleThread) SlaveConnection.get(SlaveType.Shuttle, device.getId().intValue()); if (shuttleThread == null) { continue; } ShuttleProtocol status = shuttleThread.getStatus(); data.add(status); } zy-asrs-wcs/src/main/java/com/zy/asrs/wcs/rcs/thread/LiftThread.java
@@ -3,6 +3,7 @@ import com.zy.asrs.wcs.common.ExecuteSupport; import com.zy.asrs.wcs.core.model.command.LiftCommand; import com.zy.asrs.wcs.rcs.entity.Device; import com.zy.asrs.wcs.rcs.model.enums.LiftProtocolStatusType; import com.zy.asrs.wcs.rcs.model.protocol.LiftProtocol; public interface LiftThread extends ThreadHandler{ @@ -25,6 +26,10 @@ boolean isIdle(ExecuteSupport support);//是否空闲 boolean setProtocolStatus(LiftProtocolStatusType status);//设置工作状态 boolean setSyncTaskNo(Integer taskNo);//设置工作号 //***************获取命令***************** LiftCommand getMoveCommand(Integer taskNo, Integer sourceLev, Integer targetLev, Integer mode);//提升机移动 zy-asrs-wcs/src/main/java/com/zy/asrs/wcs/rcs/thread/impl/NyLiftThread.java
@@ -21,7 +21,6 @@ import com.zy.asrs.wcs.rcs.entity.Device; import com.zy.asrs.wcs.rcs.entity.DeviceDataLog; import com.zy.asrs.wcs.rcs.model.enums.LiftProtocolStatusType; import com.zy.asrs.wcs.rcs.model.enums.SlaveType; import com.zy.asrs.wcs.rcs.model.protocol.LiftProtocol; import com.zy.asrs.wcs.rcs.service.DeviceDataLogService; import com.zy.asrs.wcs.rcs.thread.LiftThread; @@ -29,7 +28,6 @@ import lombok.extern.slf4j.Slf4j; import java.text.MessageFormat; import java.text.SimpleDateFormat; import java.util.*; @Slf4j @@ -302,6 +300,18 @@ } @Override public synchronized boolean setProtocolStatus(LiftProtocolStatusType status) { this.liftProtocol.setProtocolStatus(status); return true; } @Override public synchronized boolean setSyncTaskNo(Integer taskNo) { this.liftProtocol.setTaskNo(taskNo); return true; } @Override public LiftCommand getMoveCommand(Integer taskNo, Integer sourceLev, Integer targetLev, Integer mode) { /** * 任务类型 zy-asrs-wcs/src/main/java/com/zy/asrs/wcs/rcs/thread/impl/SurayLiftThread.java
@@ -2,18 +2,13 @@ import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSONObject; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.zy.asrs.common.utils.HttpHandler; import com.zy.asrs.framework.common.DateUtils; import com.zy.asrs.framework.common.SpringUtils; import com.zy.asrs.framework.exception.CoolException; import com.zy.asrs.wcs.common.ExecuteSupport; import com.zy.asrs.wcs.core.entity.Loc; import com.zy.asrs.wcs.core.model.command.LiftCommand; import com.zy.asrs.wcs.core.model.command.ShuttleCommand; import com.zy.asrs.wcs.core.model.enums.LiftCommandModeType; import com.zy.asrs.wcs.core.model.enums.ShuttleCommandModeType; import com.zy.asrs.wcs.core.service.LocService; import com.zy.asrs.wcs.rcs.News; import com.zy.asrs.wcs.rcs.cache.OutputQueue; import com.zy.asrs.wcs.rcs.entity.DeviceDataLog; @@ -28,7 +23,6 @@ import java.text.MessageFormat; import java.text.SimpleDateFormat; import java.util.Base64; import java.util.Date; import java.util.HashMap; @@ -333,6 +327,18 @@ return false; } @Override public boolean setProtocolStatus(LiftProtocolStatusType status) { this.liftProtocol.setProtocolStatus(status); return true; } @Override public boolean setSyncTaskNo(Integer taskNo) { this.liftProtocol.setTaskNo(taskNo); return true; } //***************设备层通讯-不同厂商设备通讯方案不一致*************** //请求登录 zy-asrs-wcs/src/main/java/com/zy/asrs/wcs/rcs/ws/LiftWebSocket.java
New file @@ -0,0 +1,171 @@ package com.zy.asrs.wcs.rcs.ws; import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSONObject; import com.zy.asrs.framework.common.R; import com.zy.asrs.framework.common.SpringUtils; import com.zy.asrs.wcs.common.config.ConfigProperties; import com.zy.asrs.wcs.common.security.JwtSubject; import com.zy.asrs.wcs.rcs.model.protocol.LiftProtocol; import com.zy.asrs.wcs.rcs.service.LiftService; import com.zy.asrs.wcs.rcs.ws.model.WebSocketMessage; import com.zy.asrs.wcs.utils.JwtUtil; import io.jsonwebtoken.Claims; import lombok.Data; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import org.springframework.stereotype.Service; import javax.websocket.*; import javax.websocket.server.ServerEndpoint; import java.io.IOException; import java.util.List; import java.util.concurrent.CopyOnWriteArraySet; @Component @Slf4j @Service @ServerEndpoint("/ws/lift/websocket") @Data public class LiftWebSocket { //客户端在线人数 private static int onlineClient = 0; //客户端池 private static CopyOnWriteArraySet<LiftWebSocket> webSocketServers = new CopyOnWriteArraySet<>(); private Session session; private String username; private Long hostId; //管道ID private String sessionId; @OnOpen public void onOpen(Session session) { this.session = session; this.sessionId = session.getId(); //将websocket对象进行保存 webSocketServers.add(this); //添加在线人数 addOnlineClient(); log.info("有新窗口开始监听:" + session.getId() + ",当前在线人数为:" + getOnlineClient()); } /** * 连接关闭调用的方法 */ @OnClose public void onClose() { webSocketServers.remove(this); //从set中删除 subOnlineClient(); //在线数减1 log.info("关闭的连接:" + sessionId); log.info("有一连接关闭!当前在线人数为" + getOnlineClient()); } /** * 收到客户端消息后调用的方法 * @ Param message 客户端发送过来的消息 */ @OnMessage public void onMessage(String message, Session session) throws IOException { LiftService liftService = SpringUtils.getBean(LiftService.class); WebSocketMessage socketMessage = JSON.parseObject(message, WebSocketMessage.class); if (socketMessage.getUrl().equals("login")) { try { // 解析token ConfigProperties configProperties = SpringUtils.getBean(ConfigProperties.class); JSONObject data = JSON.parseObject(socketMessage.getData()); Claims claims = JwtUtil.parseToken(data.getString("token"), configProperties.getTokenKey()); JwtSubject jwtSubject = JwtUtil.getJwtSubject(claims); this.username = jwtSubject.getUsername(); this.hostId = jwtSubject.getHostId(); socketMessage.setData(JSON.toJSONString(R.ok("auth success"))); } catch (Exception e) { e.printStackTrace(); socketMessage.setData(JSON.toJSONString(R.error("auth fail"))); } this.sendMessage(JSON.toJSONString(socketMessage)); } else if (socketMessage.getUrl().equals("/lift/status/list")) { if (this.hostId != null) { List<LiftProtocol> data = liftService.getLiftStatusList(this.hostId); socketMessage.setData(JSON.toJSONString(data)); this.sendMessage(JSON.toJSONString(socketMessage)); } } // log.info("收到来自连接:" + sessionId + "的信息:" + message); } /** * @ Param session * @ Param error */ @OnError public void onError(Session session, Throwable error) { log.error("发生错误"); error.printStackTrace(); } /** * 实现服务器主动推送 */ public void sendMessage(String message) throws IOException { this.session.getBasicRemote().sendText(message); } /** * 服务器主动推送给指定用户 */ public void sendMessage(String message, String account) throws IOException { for (LiftWebSocket item : webSocketServers) { item.sendMessage(message); } } public void sendMessage(String message, int userId) throws IOException { for (LiftWebSocket item : webSocketServers) { item.sendMessage(message); } } /** * 服务器主动推送给指定用户 */ public static boolean sendMessageGlobal(String message, String account) throws IOException { boolean tag = false; for (LiftWebSocket item : webSocketServers) { tag = true; item.sendMessage(message); } return tag; } public static boolean sendMessageGlobal(String message, int userId) throws IOException { boolean tag = false; for (LiftWebSocket item : webSocketServers) { tag = true; item.sendMessage(message); } return tag; } public static synchronized int getOnlineClient() { return onlineClient; } public static synchronized void addOnlineClient() { LiftWebSocket.onlineClient++; } public static synchronized void subOnlineClient() { if (LiftWebSocket.onlineClient > 0) { LiftWebSocket.onlineClient--; } } } zy-asrs-wcs/src/main/java/com/zy/asrs/wcs/rcs/ws/ShuttleWebSocket.java
@@ -13,6 +13,7 @@ import io.jsonwebtoken.Claims; import lombok.Data; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import org.springframework.stereotype.Service;