This commit is contained in:
aikai 2025-06-09 11:51:42 +08:00
commit 22f58ed6b0
203 changed files with 4441 additions and 967 deletions

View File

@ -1,7 +1,9 @@
package cn.iocoder.yudao.framework.common.util.date;
import cn.hutool.core.date.LocalDateTimeUtil;
import cn.hutool.core.util.ObjectUtil;
import java.text.SimpleDateFormat;
import java.time.*;
import java.time.format.DateTimeFormatter;
import java.util.Calendar;
@ -33,6 +35,21 @@ public class DateUtils {
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyyMMdd");
return currentDate.format(formatter);
}
public static String getYearMonthDayHourMinuteSecon() {
LocalDateTime currentDate = LocalDateTime.now();
DateTimeFormatter formatter = DateTimeFormatter.ofPattern(FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND);
return currentDate.format(formatter);
}
public static String getYYYMMDD(Date date) {
if (ObjectUtil.isEmpty(date)) {
date = new Date();
}
SimpleDateFormat simpleDateFormat=new SimpleDateFormat("yyyy-MM-dd");
return simpleDateFormat.format(date);
}
/**
* LocalDateTime 转换成 Date
*

View File

@ -251,6 +251,7 @@ public class GlobalExceptionHandler {
for (StackTraceElement stackTrace : stackTraces) {
if (ObjUtil.notEqual(stackTrace.getClassName(), ServiceExceptionUtil.class.getName())) {
log.warn("[serviceExceptionHandler]\n\t{}", stackTrace);
log.warn("异常信息 :{}",ex.getMessage());
break;
}
}

View File

@ -17,7 +17,7 @@ import java.util.List;
public interface PathPlanningApi {
String PREFIX = ApiConstants.PREFIX + "/config";
@PostMapping(PREFIX + "/synchronousPoint")
/* @PostMapping(PREFIX + "/synchronousPoint")
@Operation(summary = "同步ware_position_map_line的点位信息")
void synchronousPointToPP(@RequestBody PositionMapLinePathDTO relatedPathNode, @RequestParam("topic") String topic);
@ -28,5 +28,5 @@ public interface PathPlanningApi {
@PostMapping(PREFIX + "/synchronousLineObject")
@Operation(summary = "同步Object信息给PP")
void synchronousLineObject(@RequestBody Object obj, @RequestParam("topic") String topic);
void synchronousLineObject(@RequestBody Object obj, @RequestParam("topic") String topic);*/
}

View File

@ -0,0 +1,13 @@
package cn.iocoder.yudao.module.mqtt.api.path.dto;
import lombok.Data;
@Data
public class PathToRobotArgDTO {
private Long floor;
private String areaId;
private String mapName;
private String poseId;
private PathToRobotArgPoseDTO pose2d;
}

View File

@ -0,0 +1,12 @@
package cn.iocoder.yudao.module.mqtt.api.path.dto;
import lombok.Data;
@Data
public class PathToRobotArgPoseDTO {
private Double x;
private Double y;
private Double yaw;
}

View File

@ -0,0 +1,25 @@
package cn.iocoder.yudao.module.mqtt.api.path.dto;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class PathToRobotDTO {
//这个实体类的信息,不能修改
//这个实体类的信息,不能修改
//这个实体类的信息,不能修改
//这个实体类的信息,不能修改
//这个实体类的信息,不能修改
//这个实体类的信息,不能修改
private String orderType;
private Integer isCommandEnd;
private String robotNo;
private String commandType;
private PathToRobotArgDTO arg;
}

View File

@ -15,7 +15,7 @@ import java.util.List;
public class PositionMapItemSynDTO {
@Schema(description = "主键ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "31007")
private Long id;
private String id;
@Schema(description = "坐标x轴")
private Double x;

View File

@ -18,7 +18,7 @@ public interface RobotTaskApi {
String PREFIX = ApiConstants.PREFIX + "/config";
@PostMapping(PREFIX + "/distribute/tasks")
/*@PostMapping(PREFIX + "/distribute/tasks")
@Operation(summary = "下发任务给车机")
void sendTaskToRobot(@Valid @RequestBody List<RobotAcceptTaskDTO> robotTaskDOS );
void sendTaskToRobot(@Valid @RequestBody List<RobotAcceptTaskDTO> robotTaskDOS );*/
}

View File

@ -1,6 +1,7 @@
package cn.iododer.yudao.module.mqtt.api.common;
import cn.iocoder.yudao.module.mqtt.api.common.CommonApi;
import cn.iododer.yudao.module.mqtt.config.MqttFactory;
import cn.iododer.yudao.module.mqtt.util.MqttUtils;
import com.alibaba.fastjson.JSON;
import lombok.extern.slf4j.Slf4j;

View File

@ -26,7 +26,7 @@ public class PathPlanningApiImpl implements PathPlanningApi {
* @param relatedPathNode
* @param topic
*/
@Override
/*@Override
public void synchronousPointToPP(PositionMapLinePathDTO relatedPathNode, String topic) {
try {
mqttUtils.pub(topic, JSON.toJSONString(relatedPathNode));
@ -36,11 +36,11 @@ public class PathPlanningApiImpl implements PathPlanningApi {
}
}
/**
*//**
* 同步ware_position_map_item的点位信息
* @param positionMapItemSynDTOS
* @param topic
*/
*//*
@Override
public void synchronousAllItemToPP(List<PositionMapItemSynDTO> positionMapItemSynDTOS, String topic) {
try {
@ -59,5 +59,5 @@ public class PathPlanningApiImpl implements PathPlanningApi {
} catch (MqttException e) {
log.info("同步信息给PP--完成--异常 :{}",e);
}
}
}*/
}

View File

@ -23,7 +23,7 @@ public class RobotTaskApiImpl implements RobotTaskApi {
@Autowired
private MqttUtils mqttUtils;
@Override
/*@Override
public void sendTaskToRobot(List<RobotAcceptTaskDTO> robotTaskDOS) {
for (RobotAcceptTaskDTO robotTaskDO : robotTaskDOS) {
log.info("发送MQTT消息 :{}",JSON.toJSONString(robotTaskDO));
@ -33,5 +33,5 @@ public class RobotTaskApiImpl implements RobotTaskApi {
log.info("消息发送异常 :{}",e.getMessage());
}
}
}
}*/
}

View File

@ -1,15 +1,15 @@
package cn.iododer.yudao.module.mqtt.config;
import cn.iododer.yudao.module.mqtt.service.MqttService;
import cn.iododer.yudao.module.mqtt.service.RobotTaskStatusServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.eclipse.paho.client.mqttv3.IMqttAsyncClient;
import org.eclipse.paho.client.mqttv3.IMqttDeliveryToken;
import org.eclipse.paho.client.mqttv3.MqttCallback;
import org.eclipse.paho.client.mqttv3.MqttMessage;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import java.nio.charset.StandardCharsets;
/**
* MQTT回调
*/
@ -35,7 +35,7 @@ public class MqttCallBack implements MqttCallback {
*/
@Override
public void messageArrived(String topic, MqttMessage mqttMessage) throws Exception {
String msg = new String(mqttMessage.getPayload());
String msg = new String(mqttMessage.getPayload(), StandardCharsets.UTF_8);
// log.info("[MQTT]接收当前消息为 :{}", msg);
try {

View File

@ -147,6 +147,8 @@ public class MqttFactory {
return BeanUtils.getBean(RobotUpdatePalletHeightServiceImpl.class);
case ROBOT_OBSTACLES_STATUS:
return BeanUtils.getBean(RobotObstaclesStatusServiceImpl.class);
case ROBOT_WIRELESS_SIGNAL_STATUS:
return BeanUtils.getBean(RobotWirelessSignalStatusServiceImpl.class);
case PLANNING_INIT_DATA:
return BeanUtils.getBean(PathPlanningInitDataServiceImpl.class);
case PLANNING_DISTRIBUTION_TASK:

View File

@ -22,6 +22,7 @@ public enum DefineSubTopicEnum {
ROBOT_WORK_STATUS("ROBOT_WORK_STATUS", 2,"作业实时行为上报"),
ROBOT_UPDATE_PALLET_HEIGHT("UPDATE_PALLET_HEIGHT", 2,"放货后货物高度反馈和取货后货物高度反馈"),
ROBOT_OBSTACLES_STATUS("ROBOT_OBSTACLES_STATUS", 2,"障碍物状态上报"),
ROBOT_WIRELESS_SIGNAL_STATUS("ROBOT_WIRELESS_SIGNAL_STATUS", 2,"信号强度上报"),
PLANNING_INIT_DATA("SYNCHRONOUS_ALL_MAP_REQUEST", 2,"路径规划需要初始数据上报"),
PLANNING_DISTRIBUTION_TASK("TASK_ASSIGNMENT_FEEDBACK", 2,"路径规划任务分配上报"),
PLANNING_DISTRIBUTION_FAIL("TASK_ASSIGNMENT_FAIL", 2,"路径规划失败上报"),

View File

@ -22,7 +22,7 @@ public class RobotStatusServiceImpl implements MqttService {
*/
@Override
public void analysisMessage(String message) {
log.info("处理RobotStatusServiceImpl的消息 :{}", message);
// log.info("处理RobotStatusServiceImpl的消息 :{}", message);
RobotPoseStatusDTO robotStatusData = JSON.parseObject(message, RobotPoseStatusDTO.class);
robotStatusApi.robotStatusUpdate(robotStatusData);
}

View File

@ -0,0 +1,22 @@
package cn.iododer.yudao.module.mqtt.service;
import cn.iocoder.yudao.module.remote.api.path.RemotePathApi;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
@Slf4j
@Service
public class RobotWirelessSignalStatusServiceImpl implements MqttService{
@Resource
private RemotePathApi remotePathApi;
@Override
public void analysisMessage(String message) {
log.info("车辆信号上报 :{}",message);
remotePathApi.wirelessSignalStatus(message);
}
}

View File

@ -12,6 +12,8 @@ spring:
config: # 【注册中心】配置项
namespace: dev # 命名空间。这里使用 dev 开发环境
group: DEFAULT_GROUP # 使用的 Nacos 配置分组,默认为 DEFAULT_GROUP
mqtt:
charset: UTF-8
# Lock4j 配置项
lock4j:

View File

@ -12,6 +12,8 @@ spring:
config: # 【注册中心】配置项
namespace: dev # 命名空间。这里使用 dev 开发环境
group: DEFAULT_GROUP # 使用的 Nacos 配置分组,默认为 DEFAULT_GROUP
mqtt:
charset: UTF-8
# Lock4j 配置项
lock4j:
@ -33,6 +35,7 @@ management:
mqtt:
# host: tcp://123.57.12.40:1883
host: tcp://127.0.0.1:1883
# host: tcp://10.10.7.195:1883
username: adminuser
password: adminuser
qos: 2

View File

@ -12,6 +12,8 @@ spring:
config: # 【注册中心】配置项
namespace: dev # 命名空间。这里使用 dev 开发环境
group: DEFAULT_GROUP # 使用的 Nacos 配置分组,默认为 DEFAULT_GROUP
mqtt:
charset: UTF-8
# Lock4j 配置项
lock4j:
@ -31,7 +33,7 @@ management:
# MQTT
mqtt:
# host: tcp://192.168.0.54:1883
# host: tcp://123.57.12.40:1883
host: tcp://127.0.0.1:1883
username: adminuser
password: adminuser

View File

@ -31,7 +31,7 @@
<!-- 启动服务时,是否清理历史日志,一般不建议清理 -->
<cleanHistoryOnStart>${LOGBACK_ROLLINGPOLICY_CLEAN_HISTORY_ON_START:-false}</cleanHistoryOnStart>
<!-- 日志文件,到达多少容量,进行滚动 -->
<maxFileSize>${LOGBACK_ROLLINGPOLICY_MAX_FILE_SIZE:-10MB}</maxFileSize>
<maxFileSize>50MB</maxFileSize>
<!-- 日志文件的总大小0 表示不限制 -->
<totalSizeCap>${LOGBACK_ROLLINGPOLICY_TOTAL_SIZE_CAP:-0}</totalSizeCap>
<!-- 日志文件的保留天数 -->

View File

@ -16,4 +16,7 @@ public interface RemotePathApi {
@Operation(summary = "远遥同步车辆导航行走路程信息")
void remoteDistanceInformation(@RequestParam("message") String message);
@PostMapping(PREFIX + "/wirelessSignalStatus")
@Operation(summary = "车辆信号信息")
void wirelessSignalStatus(@RequestParam("message") String message);
}

View File

@ -0,0 +1,15 @@
package cn.iocoder.yudao.module.remote.api.path.dto;
import lombok.Data;
@Data
public class RemoteRobotWirelessSignalDTO {
private String mac;
/**
* 整型单位dBm
*/
private String wirelessSignal;
}

View File

@ -1,6 +1,7 @@
package cn.iocoder.yudao.module.remote.api.path;
import cn.iocoder.yudao.module.remote.api.path.dto.RemoteRobotDistanceInformationDTO;
import cn.iocoder.yudao.module.remote.api.path.dto.RemoteRobotWirelessSignalDTO;
import cn.iocoder.yudao.module.remote.service.robot.RemoteRobotService;
import cn.iocoder.yudao.module.remote.util.redis.RedisUtil;
import com.alibaba.fastjson.JSON;
@ -31,5 +32,15 @@ public class RemotePathApiImpl implements RemotePathApi{
remoteRobotService.remoteDistanceInformation(data);
}
/**
* 车辆信号信息
* @param message
*/
@Override
public void wirelessSignalStatus(String message) {
RemoteRobotWirelessSignalDTO data = JSON.parseObject(message, RemoteRobotWirelessSignalDTO.class);
remoteRobotService.sendRobotWirelessSignalStatus(data);
}
}

View File

@ -1,13 +1,14 @@
package cn.iocoder.yudao.module.remote.api.robot;
import cn.hutool.core.util.ObjectUtil;
import cn.iocoder.yudao.module.remote.config.ip.IpProperties;
import cn.iocoder.yudao.module.remote.controller.admin.robot.dto.Cockpit;
import cn.iocoder.yudao.module.remote.controller.admin.robot.dto.RemoteControllerSocketDTO;
import cn.iocoder.yudao.module.remote.enums.robot.RemoteIpTypeEnum;
import cn.iocoder.yudao.module.remote.util.crc.CRCUtil;
import cn.iocoder.yudao.module.system.api.remote.dto.RemoteRobotTransferDTO;
import com.alibaba.fastjson.JSON;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
@ -28,18 +29,13 @@ import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.REMOTE_ROB
@Component
@Slf4j
public class RemoteControllerProcessor {
private final ConcurrentHashMap<String, RemoteControllerSocketDTO> cache = new ConcurrentHashMap<>();
public final ConcurrentHashMap<String, RemoteControllerSocketDTO> cache = new ConcurrentHashMap<>();
private final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);
public final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);
@Value("${remote.msg}")
private String defaultMsg;
@Value("${remote.controller-ip}")
private String remoteControllerIp;
@Value("${remote.controller-port}")
private int remoteControllerPort;
@Value("${remote.cockpit-time-out}")
private int cockpitTimeOut;
@ -53,35 +49,43 @@ public class RemoteControllerProcessor {
private final String ONE = "01";
private final String TWO = "02";
public void addCache(RemoteRobotTransferDTO dto) {
RemoteControllerSocketDTO remoteControllerSocketDTO = cache.get(remoteControllerIp);
log.info("缓存的数据 :{}", JSON.toJSONString(remoteControllerSocketDTO));
@Autowired
private IpProperties ipProperties;
public void addCache(RemoteRobotTransferDTO dto,String ip) {
Cockpit cockpit = ipProperties.getCockpitByIp(ip);
String cockpitIp = cockpit.getControllerIp();
int cockpitPort = cockpit.getControllerPort();
RemoteControllerSocketDTO remoteControllerSocketDTO = cache.get(cockpitIp);
log.info("是否为空 :{}",ObjectUtil.isEmpty(remoteControllerSocketDTO));
if (ObjectUtil.isNotEmpty(remoteControllerSocketDTO)) {
try {
Socket socket = remoteControllerSocketDTO.getSocket();
if (socket != null && !socket.isClosed()) {
socket.close();
}
log.info("关闭socket :{}", remoteControllerIp);
log.info("关闭socket :{}", cockpitIp);
} catch (IOException e) {
log.error("关闭socket出现异常 :{}", remoteControllerIp);
log.error("关闭socket出现异常 :{}", cockpitIp);
throw new RuntimeException(e);
}
} else {
remoteControllerSocketDTO = new RemoteControllerSocketDTO();
}
remoteControllerSocketDTO.setHost(remoteControllerIp);
remoteControllerSocketDTO.setPort(remoteControllerPort);
remoteControllerSocketDTO.setControllerIp(cockpitIp);
remoteControllerSocketDTO.setControllerPort(cockpitPort);
Socket socket = new Socket();
try {
socket.connect(new InetSocketAddress(remoteControllerIp, remoteControllerPort), 1000);
socket.setKeepAlive(true);
socket.connect(new InetSocketAddress(cockpitIp, cockpitPort), 500);
remoteControllerSocketDTO.setSocket(socket);
} catch (IOException e) {
log.error("添加socket失败 :{}", e);
throw exception(REMOTE_ROBOT_CONNECT_FAIL);
}
setMsg(remoteControllerSocketDTO, RemoteIpTypeEnum.ONE.getType(), dto);
cache.put(remoteControllerIp, remoteControllerSocketDTO);
cache.put(cockpitIp, remoteControllerSocketDTO);
}
/**
@ -108,7 +112,7 @@ public class RemoteControllerProcessor {
String portHex = Integer.toHexString(dto.getRobotPort().intValue());
String portHexOne = portHex.substring(0, 2);
String portHexTwo = portHex.substring(2);
msg = msg + " " + portHexOne + " " + portHexTwo;
msg = msg + " " + portHexTwo + " " + portHexOne;
if (cockpitTimeOut > 0) {
msg = msg + " " + ONE + " " + Integer.toHexString(cockpitTimeOut);
} else {
@ -136,34 +140,38 @@ public class RemoteControllerProcessor {
remoteControllerSocket.setMsg(msg);
}
public void remoteCache(RemoteRobotTransferDTO dto) {
RemoteControllerSocketDTO remoteControllerSocketDTO = cache.get(remoteControllerIp);
public void remoteCache(RemoteRobotTransferDTO dto,String ip) {
Cockpit cockpit = ipProperties.getCockpitByIp(ip);
String cockpitIp = cockpit.getControllerIp();
RemoteControllerSocketDTO remoteControllerSocketDTO = cache.get(cockpitIp);
if (ObjectUtil.isEmpty(remoteControllerSocketDTO)) {
return;
}
setMsg(remoteControllerSocketDTO, RemoteIpTypeEnum.THREE.getType(), dto);
cache.remove(remoteControllerIp);
cache.remove(cockpitIp);
Socket socket = remoteControllerSocketDTO.getSocket();
if (socket == null ||socket.isClosed()) {
if (socket == null || socket.isClosed()) {
try {
socket = new Socket();
socket.connect(new InetSocketAddress(remoteControllerIp, remoteControllerPort), 1000);
log.info("连接新的的socket");
socket.setKeepAlive(true);
socket.connect(new InetSocketAddress(cockpitIp, cockpit.getControllerPort()), 1000);
} catch (IOException e) {
log.error("连接socket出现异常 :{}", remoteControllerIp);
log.error("连接socket出现异常 :{}", cockpitIp);
}
}
OutputStream os = null;
try {
os = socket.getOutputStream();
log.info("断开连接 :{} ,对应的IP :{}", remoteControllerSocketDTO.getMsg(), remoteControllerSocketDTO.getHost());
log.info("断开连接 :{} ,对应的IP :{}", remoteControllerSocketDTO.getMsg(), remoteControllerSocketDTO.getControllerIp());
os.write(remoteControllerSocketDTO.getMsg().getBytes());
socket.shutdownInput();
socket.close();
log.info("关闭socket :{}", remoteControllerIp);
log.info("关闭socket :{}", cockpitIp);
} catch (IOException e) {
log.error("关闭socket出现异常 :{}", remoteControllerIp);
log.error("关闭socket出现异常 :{}", cockpitIp);
} finally {
if (ObjectUtil.isNotEmpty(os)) {
try {
@ -173,41 +181,28 @@ public class RemoteControllerProcessor {
}
}
remoteCache(dto);
remoteCache(dto,ip);
}
public RemoteControllerProcessor() {
/*public RemoteControllerProcessor() {
// 每秒执行一次 - 处理并发送数据 - 避免数据丢失
scheduler.scheduleAtFixedRate(this::processAndSend, 150, 150, TimeUnit.MILLISECONDS);
}
}*/
private void processAndSend() {
public void processAndSend() {
if (ObjectUtil.isEmpty(cache)) {
return;
}
log.info("socket发送数据开始");
// log.info("socket发送数据开始");
for (Map.Entry<String, RemoteControllerSocketDTO> v : cache.entrySet()) {
RemoteControllerSocketDTO remoteControllerSocketDTO = v.getValue();
if (ObjectUtil.isEmpty(remoteControllerSocketDTO)) {
remoteControllerSocketDTO = new RemoteControllerSocketDTO();
remoteControllerSocketDTO.setHost(v.getKey());
remoteControllerSocketDTO.setPort(remoteControllerPort);
try {
Socket socket = new Socket();
socket.connect(new InetSocketAddress(v.getKey(), remoteControllerPort), 1000);
remoteControllerSocketDTO.setSocket(socket);
} catch (IOException e) {
throw new RuntimeException(e);
}
cache.put(v.getKey(), remoteControllerSocketDTO);
}
Socket socket = remoteControllerSocketDTO.getSocket();
if (socket == null || socket.isClosed()) {
socket = new Socket();
try {
socket.connect(new InetSocketAddress(v.getKey(), remoteControllerPort), 1000);
socket.connect(new InetSocketAddress(v.getKey(), remoteControllerSocketDTO.getControllerPort()), 1000);
remoteControllerSocketDTO.setSocket(socket);
} catch (IOException e) {
log.error("socket重连异常 :{}", e);
@ -218,8 +213,8 @@ public class RemoteControllerProcessor {
try {
os = socket.getOutputStream();
String str = remoteControllerSocketDTO.getMsg();
log.info("socket推送的数据 :{}", str);
os.write(remoteControllerSocketDTO.getMsg().getBytes());
log.info("socket推送的数据 :{}", str);
} catch (IOException e) {
log.error("socket发送异常 :{}", e);
} finally {
@ -230,7 +225,6 @@ public class RemoteControllerProcessor {
}
}
}
log.info("socket发送数据成功");
}
}

View File

@ -0,0 +1,36 @@
package cn.iocoder.yudao.module.remote.api.robot;
import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
@EnableScheduling
@Component
@Slf4j
public class RemoteScheduledTasks {
private static final ExecutorService fixedThreadPool = Executors.newFixedThreadPool(3);
@Resource
private RemoteControllerProcessor remoteControllerProcessor;
// 这个方法将每200毫秒执行一次
@Scheduled(fixedDelay = 300, timeUnit = TimeUnit.MILLISECONDS)
public void executeTask() {
fixedThreadPool.execute(new Runnable() {
@Override
public void run() {
remoteControllerProcessor.processAndSend();
}
});
}
}

View File

@ -0,0 +1,31 @@
package cn.iocoder.yudao.module.remote.config.ip;
import cn.iocoder.yudao.module.remote.controller.admin.robot.dto.Cockpit;
import lombok.Getter;
import lombok.Setter;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
import java.util.List;
@Component
@ConfigurationProperties(prefix ="remote",ignoreInvalidFields = true)
@Getter
@Setter
public class IpProperties {
private List<Cockpit> cockpit;
public Cockpit getCockpitByIp(String ip) {
for (Cockpit v : cockpit) {
if (ip.equals(v.getIpcIp())){
return v;
}
}
Cockpit data = new Cockpit();
data.setControllerIp("127.0.0.1");
data.setControllerPort(9000);
return data;
}
}

View File

@ -8,4 +8,6 @@ public class RobotTaskChcheConstant {
//机器人编号和mac地址映射(通过机器人编号查询mac地址) (拼接的是机器人编号)
public static String ROBOT_GET_MAC_BY_NO = "robot:information:getMac:ByNo";
//机器人mac地址和机器人编号映射(通过mac地址查询机器人编号) (拼接的是mac地址)
public static String ROBOT_GET_ROBOTNO_BY_MAC = "robot:information:getRobotNo:ByMac";
}

View File

@ -0,0 +1,14 @@
package cn.iocoder.yudao.module.remote.controller.admin.robot.dto;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
@Data
public class Cockpit {
@Schema(description = "工控机IP")
private String ipcIp;
@Schema(description = "驾舱端口")
private int controllerPort;
@Schema(description = "驾舱IP")
private String controllerIp;
}

View File

@ -1,13 +1,16 @@
package cn.iocoder.yudao.module.remote.controller.admin.robot.dto;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import java.net.Socket;
@Data
public class RemoteControllerSocketDTO {
private String host;
private int port;
@Schema(description = "驾舱IP")
private String controllerIp;
@Schema(description = "驾舱端口")
private int controllerPort;
private Socket socket;
private String msg;
}

View File

@ -3,6 +3,8 @@ package cn.iocoder.yudao.module.remote.controller.admin.robot.dto;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import javax.validation.constraints.Max;
import javax.validation.constraints.Min;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull;
@ -10,6 +12,8 @@ import javax.validation.constraints.NotNull;
public class RemoteRobotChangeModeDTO {
@Schema(description = "远遥模式(0:自动模式, 1:手动模式, 2:自由模式)")
@NotNull(message = "请选择远遥模式")
@Max(value = 2,message = "请选择远遥模式")
@Min(value = 0,message = "请选择远遥模式")
private Integer remoteMode = 0;
@Schema(description = "车辆编号")

View File

@ -37,7 +37,7 @@ public class LoginServiceImpl implements LoginService {
@Override
public Boolean checkCommunication(LoginCheckDTO loginCheckDTO) {
HttpComponentsClientHttpRequestFactory factory = new HttpComponentsClientHttpRequestFactory();
factory.setConnectTimeout(5 * 1000);
factory.setConnectTimeout(2 * 1000);
RestTemplate restTemplate = new RestTemplate(factory);
String url = "http://" + loginCheckDTO.getSystemIp() + ":" + loginCheckDTO.getSystemPort() + checkUrl;
LinkedMultiValueMap<String, String> headers = new LinkedMultiValueMap<>();

View File

@ -1,6 +1,7 @@
package cn.iocoder.yudao.module.remote.service.robot;
import cn.iocoder.yudao.module.remote.api.path.dto.RemoteRobotDistanceInformationDTO;
import cn.iocoder.yudao.module.remote.api.path.dto.RemoteRobotWirelessSignalDTO;
import cn.iocoder.yudao.module.remote.controller.admin.robot.dto.PositionMapRespDTO;
import cn.iocoder.yudao.module.remote.controller.admin.robot.dto.RemoteRobotChangeModeDTO;
import cn.iocoder.yudao.module.remote.controller.admin.robot.dto.RemoteRobotTaskDoneDTO;
@ -76,4 +77,10 @@ public interface RemoteRobotService {
* @param data
*/
void remoteDistanceInformation(RemoteRobotDistanceInformationDTO data);
/**
* 上报车辆信号信息
* @param data
*/
void sendRobotWirelessSignalStatus(RemoteRobotWirelessSignalDTO data);
}

View File

@ -5,9 +5,12 @@ import cn.hutool.json.JSONUtil;
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.framework.tenant.core.context.TenantContextHolder;
import cn.iocoder.yudao.module.remote.api.path.dto.RemoteRobotDistanceInformationDTO;
import cn.iocoder.yudao.module.remote.api.path.dto.RemoteRobotWirelessSignalDTO;
import cn.iocoder.yudao.module.remote.api.robot.RemoteControllerProcessor;
import cn.iocoder.yudao.module.remote.api.webSocket.RequestProcessor;
import cn.iocoder.yudao.module.remote.config.ip.IpProperties;
import cn.iocoder.yudao.module.remote.constant.robot.RobotTaskChcheConstant;
import cn.iocoder.yudao.module.remote.controller.admin.robot.dto.Cockpit;
import cn.iocoder.yudao.module.remote.controller.admin.robot.dto.PositionMapRespDTO;
import cn.iocoder.yudao.module.remote.controller.admin.robot.dto.RemoteRobotChangeModeDTO;
import cn.iocoder.yudao.module.remote.controller.admin.robot.dto.RemoteRobotTaskDoneDTO;
@ -22,6 +25,7 @@ import cn.iocoder.yudao.module.system.api.remote.dto.RemoteRobotTransferDTO;
import cn.iocoder.yudao.module.system.api.robot.dto.FloorZoneDTO;
import com.alibaba.fastjson.JSON;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
@ -42,17 +46,11 @@ public class RemoteRobotServiceImpl implements RemoteRobotService {
@Resource
private RedisUtil redisUtil;
@Resource
private RequestProcessor processor;
@Resource
private RemoteControllerProcessor remoteControllerProcessor;
@Value("${remote.controller-port}")
private int remoteControllerPort;
@Value("${remote.controller-ip}")
private String remoteControllerIp;
@Autowired
private IpProperties ipProperties;
/**
* 获取地图区域对应的机器人信息
@ -127,15 +125,16 @@ public class RemoteRobotServiceImpl implements RemoteRobotService {
@Override
public void robotChangeMode(RemoteRobotChangeModeDTO data, HttpServletRequest request) {
String ip = IpUtils.getIp(request);
CommonResult<RemoteRobotTransferDTO> result = remoteRobotApi.robotChangeMode(data.getRemoteMode(), ip, data.getRobotNo(),remoteControllerPort,remoteControllerIp);
Cockpit cockpit = ipProperties.getCockpitByIp(ip);
CommonResult<RemoteRobotTransferDTO> result = remoteRobotApi.robotChangeMode(data.getRemoteMode(), ip, data.getRobotNo(),cockpit.getControllerPort(),cockpit.getControllerIp());
if (!result.isSuccess()) {
throw exception0(TASK_COMMONG_FAIL.getCode(), result.getMsg());
}
//非自动模式
if (0!= data.getRemoteMode()) {
remoteControllerProcessor.addCache(result.getData());
remoteControllerProcessor.addCache(result.getData(),ip);
}else {
remoteControllerProcessor.remoteCache(result.getData());
remoteControllerProcessor.remoteCache(result.getData(),ip);
}
}
@ -162,7 +161,7 @@ public class RemoteRobotServiceImpl implements RemoteRobotService {
return;
}
remoteControllerProcessor.remoteCache(result.getData());
remoteControllerProcessor.remoteCache(result.getData(),ip);
}
/**
@ -203,8 +202,23 @@ public class RemoteRobotServiceImpl implements RemoteRobotService {
RobotDistanceInformationDTO build =
RobotDistanceInformationDTO.builder().linearSpeed(floorZone.getLinearSpeed()).robotNo(data.getRobotNo())
.endDistance(data.getEndDistance()).nextRadian(data.getNextRadian()).message(msg).build();
processor.handleRequest(floorZone.getFloor() + "_" + floorZone.getArea(),
mac, JSONUtil.toJsonStr(build));
/*processor.handleRequest(floorZone.getFloor() + "_" + floorZone.getArea(),
mac, JSONUtil.toJsonStr(build));*/
}
/**
* 上报车辆信息信息
* @param data
*/
@Override
public void sendRobotWirelessSignalStatus(RemoteRobotWirelessSignalDTO data) {
TenantContextHolder.setTenantId(1L);
String robotNo = (String) redisUtil.get(RobotTaskChcheConstant.ROBOT_GET_ROBOTNO_BY_MAC + data.getMac());
if (ObjectUtil.isEmpty(robotNo)) {
robotNo = remoteRobotApi.getRobotNoByMac(data.getMac());
}
log.info("车辆编号 :{}",robotNo);
}
/**

View File

@ -1,14 +1,20 @@
package cn.iocoder.yudao.module.remote.service.speed;
import cn.hutool.core.util.ObjectUtil;
import cn.iocoder.yudao.module.system.api.remote.RemoteRobotMaxSpeedApi;
import cn.iocoder.yudao.module.system.api.remote.dto.RemoteRobotMaxSpeedDTO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.Collections;
import java.util.List;
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception0;
import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.*;
@Slf4j
@Service
public class RemoteRobotMaxSpeedServiceImpl implements RemoteRobotMaxSpeedService{
@ -16,6 +22,9 @@ public class RemoteRobotMaxSpeedServiceImpl implements RemoteRobotMaxSpeedServic
@Resource
private RemoteRobotMaxSpeedApi remoteRobotMaxSpeedApi;
@Value("${remote.robot-max-speed:5}")
private int robotMaxSpeed;
@Override
public List<RemoteRobotMaxSpeedDTO> getRobotMaxSpeedPage() {
return remoteRobotMaxSpeedApi.getRobotMaxSpeedPage();
@ -23,6 +32,15 @@ public class RemoteRobotMaxSpeedServiceImpl implements RemoteRobotMaxSpeedServic
@Override
public void updateRobotMaxSpeedPage(List<RemoteRobotMaxSpeedDTO> list) {
for (RemoteRobotMaxSpeedDTO remoteRobotMaxSpeedDTO : list) {
int speed = ObjectUtil.isEmpty(remoteRobotMaxSpeedDTO.getMaxSpeed()) ? 0 : Integer.parseInt(remoteRobotMaxSpeedDTO.getMaxSpeed());
if (speed <= 0) {
throw exception(REMOTE_ROBOT_SPEED_EMPTY);
}else if (speed > robotMaxSpeed) {
String str = REMOTE_ROBOT_MAX_SPEED_LIMIT.getMsg() + " 最大限速为 " +robotMaxSpeed +" m/s";
throw exception0(REMOTE_ROBOT_MAX_SPEED_LIMIT.getCode(),str);
}
}
remoteRobotMaxSpeedApi.updateRobotMaxSpeedPage(list);
}

View File

@ -53,9 +53,15 @@ logging:
name: ${user.home}/logs/${spring.application.name}.log # 日志文件名,全路径
remote:
controller-port: 9000
controller-ip: 127.0.0.1
cockpit: # 远遥控制车辆IP和端口
- controllerPort: 9002
controllerIp: 127.0.0.2
ipcIp: 127.0.0.1
- controllerPort: 9001
controllerIp: 127.0.0.3
ipcIp: 127.0.0.1
msg: AA 55 13 04 01 88 88 # 驾舱socket头信息
cockpit-time-out: 120 # 驾舱超时报警时间
industrial-control-time-out: 120 # 工控通信超时报警时间
robot-communication-time-out: 120 # 车辆通信超时报警时间
robot-communication-time-out: 120 # 车辆通信超时报警时间
robot-max-speed: 5 # 远遥控制车辆最大速度 m/s

View File

@ -53,10 +53,16 @@ logging:
name: C:\system\install\log/${spring.application.name}.log
remote:
controller-port: 9000
controller-ip: 127.0.0.1
cockpit: # 远遥控制车辆IP和端口
- controllerPort: 9002
controllerIp: 127.0.0.2
ipcIp: 127.0.0.1
- controllerPort: 9001
controllerIp: 127.0.0.3
ipcIp: 127.0.0.1
msg: AA 55 13 04 01 88 88 # 驾舱socket头信息
cockpit-time-out: 120 # 驾舱超时报警时间
industrial-control-time-out: 120 # 工控通信超时报警时间
robot-communication-time-out: 120 # 车辆通信超时报警时间
robot-max-speed: 5 # 远遥控制车辆最大速度 m/s

View File

@ -34,9 +34,15 @@ logging:
name: D:/project/rcs/logs/${spring.application.name}.log
remote:
controller-port: 9000
controller-ip: 10.10.110.17
cockpit: # 远遥控制车辆IP和端口
- controllerPort: 9002
controllerIp: 127.0.0.2
ipcIp: 127.0.0.1
- controllerPort: 9001
controllerIp: 127.0.0.3
ipcIp: 127.0.0.1
msg: AA 55 13 04 01 88 88 # 驾舱socket头信息
cockpit-time-out: 120 # 驾舱超时报警时间
industrial-control-time-out: 120 # 工控通信超时报警时间
robot-communication-time-out: 120 # 车辆通信超时报警时间
robot-communication-time-out: 120 # 车辆通信超时报警时间
robot-max-speed: 5 # 远遥控制车辆最大速度 m/s

View File

@ -62,4 +62,8 @@ public interface RemoteRobotApi {
@PostMapping(PREFIX + "/getMacByRobotNo")
@Operation(summary = "根据车辆编号获取MAC地址")
String getMacByRobotNo( @RequestParam(value = "robotNo") String robotNo);
@PostMapping(PREFIX + "/getRobotNoByMac")
@Operation(summary = "根据车辆MAC地址获取车辆编号")
String getRobotNoByMac( @RequestParam(value = "mac") String mac);
}

View File

@ -18,7 +18,7 @@ public class RemoteRobotStatusDTO {
private Integer remoteMode = 0;
@Schema(description = "协控(0:关闭协控, 1:开启协控, 2:不显示协控)")
private Integer collaborativeControl = 0;
private Integer collaborativeControl = 2;
@Schema(description = "车辆任务状态(3待命 , 其他都是任务中)")
private Integer robotStatus = 2;

View File

@ -14,4 +14,29 @@ public class RobotObstaclesStatusDTO {
* true表示有障碍物false表示没有障碍物
*/
public Boolean obstacles;
/**
* 左前方障碍物距离 float单位是米
*/
private String frontLeft;
/**
* 右前方障碍物距离 float单位是米
*/
private String frontRight;
/**
* 左后方障碍物距离 float单位是米
*/
private String reaLeft;
/**
* 右后方障碍物距离 float单位是米
*/
private String reaRight;
/**
* 正后方障碍物距离 float单位是米
*/
private String rearCenter;
}

View File

@ -1,5 +1,6 @@
package cn.iocoder.yudao.module.system.api.robot.dto;
import cn.iocoder.yudao.module.system.api.robot.websocket.RobotStatusDataPoseDTO;
import lombok.Data;
@Data

View File

@ -1,5 +1,6 @@
package cn.iocoder.yudao.module.system.api.robot.dto;
import cn.iocoder.yudao.module.system.api.robot.websocket.RobotStatusDataPoseDTO;
import lombok.Data;
import java.util.List;

View File

@ -11,8 +11,5 @@ public class RobotStatusDataErrorDTO {
* 错误码
*/
public String errorCode;
/**
* 错误等级
*/
public String codeLevel;
}

View File

@ -1,6 +1,5 @@
package cn.iocoder.yudao.module.system.api.robot.vo;
package cn.iocoder.yudao.module.system.api.robot.websocket;
import cn.iocoder.yudao.module.system.api.robot.dto.RobotStatusDataPoseDTO;
import lombok.Data;
import java.util.List;
@ -31,4 +30,9 @@ public class RobotInformationVO {
* 车辆即将走的点位
*/
private List<String> data;
/**
* 车辆身上的物料信息和数量
*/
private Object skuInfo;
}

View File

@ -0,0 +1,27 @@
package cn.iocoder.yudao.module.system.api.robot.websocket;
import lombok.Data;
@Data
public class RobotSkuInfoDTO {
/**
* 1:有物料 0:没有物料
*/
private Integer haveSku = 1;
/**
* 物料信息
*/
private String skuInfo;
/**
* 物料数量
*/
private Long skuNumber;
/**
* 层数
*/
private Integer locationStorey;
}

View File

@ -1,4 +1,4 @@
package cn.iocoder.yudao.module.system.api.robot.dto;
package cn.iocoder.yudao.module.system.api.robot.websocket;
import lombok.Data;
@ -16,6 +16,8 @@ public class RobotStatusDataPoseDTO {
public String floor;
//区域
public String area;
//电池剩余容量
public String batSoc;
//货叉高度
public Double forkHeight;
//电池剩余容量 废弃 从ROBOT_INFORMATION_SOC 获取电量
// public String batSoc;
}

View File

@ -0,0 +1,23 @@
package cn.iocoder.yudao.module.system.api.robot.websocket;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
@Data
public class WsWareHouseLocationDTO {
@Schema(description = "实际坐标x轴")
private String actualLocationX;
@Schema(description = "实际坐标y轴")
private String actualLocationY;
@Schema(description = "类型: 1添加 0:减少")
private Integer type = 1;
@Schema(description = "所在楼")
public String floor;
@Schema(description = "所在区")
public String area;
}

View File

@ -224,26 +224,29 @@ public interface ErrorCodeConstants {
ErrorCode TASK_CREATE_FAIL = new ErrorCode(1-002-035-110, "任务创建失败:");
ErrorCode ROBOT_DO_TASK_FAIL = new ErrorCode(1-002-035-112, "车机反馈不能接任务");
ErrorCode TASK_COMMONG_FAIL = new ErrorCode(1-002-035-113, "下发失败");
ErrorCode TASK_ASSIGN_OTHER_ROBOT = new ErrorCode(1-002-035-114, "此任务已经转移给其他车辆");
// ========== 机器人任务明细 1-002-036-000 ==========
ErrorCode TASK_DETAIL_NOT_EXISTS = new ErrorCode(1-002-036-001, "车辆任务明细不存在");
ErrorCode TASK_DETAIL_CHANGE_ROBOT = new ErrorCode(1-002-036-002, "非新单据不能修改车辆");
ErrorCode TASK_NOT_TAKE_RELEASE = new ErrorCode(1-002-036-003, "非取货任务,不能点击取货完成");
ErrorCode TASK_NOT_TAKE_RELEASE = new ErrorCode(1-002-036-003, "已经取完货,不能点击取货完成,只能点击任务完成");
// ========== 机器人任务明细 1-002-037-000 ==========
ErrorCode REDISSON_NOT_OBTAIN_LOCK = new ErrorCode(1-002-037-001, "有正在下发中的任务请稍后重试!");
ErrorCode PATH_PLANNING_DOING_DISTRIBUTE = new ErrorCode(1-002-037-002, "有正在分配的PP任务!");
// ========== 地图信息 1-002-038-000 ==========
ErrorCode AGV_UPLOAD_INFORMATION_DOES_NOT_INCLUDE_FLOOR_OR_AREA_INFORMATION = new ErrorCode(1_002_038_001, "AGV上传信息未包含楼层或区域信息");
ErrorCode AGV_FILE_UPLOAD_CONTENT_IS_EMPTY = new ErrorCode(1_002_038_002, "AGV文件上传内容为空");
ErrorCode AGV_UPLOAD_INFORMATION_DOES_NOT_INCLUDE_FLOOR_OR_AREA_INFORMATION = new ErrorCode(1_002_038_001, "车辆上传信息未包含楼层或区域信息");
ErrorCode AGV_FILE_UPLOAD_CONTENT_IS_EMPTY = new ErrorCode(1_002_038_002, "车辆文件上传内容为空");
ErrorCode PLEASE_UPLOAD_PNG_AND_YAML_FILES = new ErrorCode(1_002_038_003, "请上传png和yaml两个文件并且文件内容不为空");
ErrorCode AGV_MAP_NOT_FOUND = new ErrorCode(1_002_038_004, "找不到AGV地图信息");
ErrorCode AGV_IMAGE_CONVERSION_TO_BASE64_FAILED = new ErrorCode(1_002_038_005, "AGV图片转base64失败");
ErrorCode AGV_MAP_NOT_FOUND = new ErrorCode(1_002_038_004, "找不到车辆地图信息");
ErrorCode AGV_IMAGE_CONVERSION_TO_BASE64_FAILED = new ErrorCode(1_002_038_005, "车辆图片转base64失败");
ErrorCode THE_LINE_LIBRARY_POINTS_ARE_NOT_LOCATED_IN_THE_SAME_AREA = new ErrorCode(1_002_038_006, "线库点位不在同一区域内");
ErrorCode THERE_ARE_ALREADY_STORAGE_LOCATIONS_IN_OTHER_LINE_WAREHOUSES = new ErrorCode(1_002_038_007, "已有库位在其他线库内");
ErrorCode THERE_ARE_ALREADY_STORAGE_LOCATIONS_IN_OTHER_STORAGE_AREAS = new ErrorCode(1_002_038_008, "已有库位在其它区域内");
ErrorCode MAP_DOES_NOT_EXIST_AGV = new ErrorCode(1_002_038_009, "此楼层区域不存在车辆需要暂停或恢复");
ErrorCode MAP_EXIST_TASK_EXIST_TASK = new ErrorCode(1_002_038_010, "修改地图:此楼层区域存在处理中的任务或者库位上还有货物");
ErrorCode MAP_EXIST_BINDING_POINT = new ErrorCode(1_002_038_011, "修改地图:此楼层区域的地图交换点尚未解绑");
// ========== 机器人自动移库 1-002-039-000 ==========
ErrorCode TASK_AUTO_MOVE_NOT_EXISTS = new ErrorCode(1_002_039_001, "车辆自动移库不存在");
@ -292,7 +295,6 @@ public interface ErrorCodeConstants {
ErrorCode REMOTE_NOT_HAVE_PATH_MATCH = new ErrorCode(1_002_053_007, "车辆未匹配路网");
ErrorCode REMOTE_AUTOMATIC_CAN_NOT_CHANGE_TO_FREE = new ErrorCode(1_002_053_008, "手动模式只能切换到自动模式");
ErrorCode REMOTE_FREE_CAN_NOT_CHANGE_TO_HAND_MOVEMENT = new ErrorCode(1_002_053_009, "自由模式只能切换到自动模式");
ErrorCode REMOTE_NOT_HAVE_BINDING_ROBOT = new ErrorCode(1_002_053_010, "远遥设备未选择车辆");
ErrorCode REMOTE_TASK_HAVE_CHOOSE = new ErrorCode(1_002_053_011, "此任务已经被远遥设备选中");
ErrorCode REMOTE_TASK_NOT_OCCUR_ERROR = new ErrorCode(1_002_053_012, "此任务未发发生4级异常");
ErrorCode REMOTE_TASK_NOT_TAKE_RELEASE = new ErrorCode(1_002_053_013, "非取货或者放货任务,不能转移");
@ -300,6 +302,12 @@ public interface ErrorCodeConstants {
ErrorCode REMOTE_ROBOT_HAVE_MORE_TASK = new ErrorCode(1_002_053_015, "此车辆有一个以上的处理中任务,请先检查数据");
ErrorCode REMOTE_ROBOT_HAVE_NOT_TASK = new ErrorCode(1_002_053_016, "此车辆没有处理中的任务");
ErrorCode REMOTE_ROBOT_CONNECT_FAIL = new ErrorCode(1_002_053_017, "与远遥工控机连接失败");
ErrorCode REMOTE_TRANSFER_NOT_SAME_ROBOT = new ErrorCode(1_002_053_018, "任务转移车辆与发生异常的车辆,不能是同一台车");
ErrorCode REMOTE_ROBOT_HAVE_TASK = new ErrorCode(1_002_053_019, "此车辆有处理中的任务,不能进行任务转移。请选择其他车辆");
ErrorCode REMOTE_ROBOT_SPEED_EMPTY = new ErrorCode(1_002_053_020, "车辆速度必须大于0m/s");
ErrorCode REMOTE_ROBOT_MAX_SPEED_LIMIT = new ErrorCode(1_002_053_021, "车辆速度超过最大速度限制");
ErrorCode REMOTE_NOT_HAVE_SPEED = new ErrorCode(1_002_053_022, "查询不到车辆速度信息");
ErrorCode REMOTE_SPEED_MORE_THAN_ZERO = new ErrorCode(1_002_053_023, "车辆未停稳");
// ========== 车辆摄像头信息 1_002_054_001 ==========
ErrorCode CAMERA_NOT_EXISTS = new ErrorCode(1_002_054_001, "车辆摄像头信息不存在");
@ -317,4 +325,7 @@ public interface ErrorCodeConstants {
ErrorCode POSITION_CHANGE_POINT_BINDING_NOT_EXISTS = new ErrorCode(1_002_057_001, "区域变更点绑定不存在");
ErrorCode POSITION_CHANGE_POINT_SAME_MAP = new ErrorCode(1_002_057_002, "区域变更点绑定,不能是同一张地图");
ErrorCode POSITION_CHANGE_POINT_ALREADY_BINDING = new ErrorCode(1_002_057_003, "请勿重复绑定区域变更点");
// ========== 车辆工作时长统计 1_002_058_001 ==========
ErrorCode ROBOT_WORKING_HOURS_STATISTICS_NOT_EXISTS = new ErrorCode(1_002_058_001, "车辆工作时长统计不存在");
}

View File

@ -8,5 +8,6 @@ package cn.iocoder.yudao.module.system.enums.oauth2;
public interface OAuth2ClientConstants {
String CLIENT_ID_DEFAULT = "default";
String CLIENT_ID_REMOTE = "remote";
}

View File

@ -4,13 +4,18 @@ package cn.iocoder.yudao.module.system.api.path;
import cn.hutool.core.util.ObjectUtil;
import cn.iocoder.yudao.framework.tenant.core.context.TenantContextHolder;
import cn.iocoder.yudao.module.system.config.ratelimiter.SystemRateLimiter;
import cn.iocoder.yudao.module.system.constant.CommonConstant;
import cn.iocoder.yudao.module.system.controller.admin.path.dto.GraphMatchDataDTO;
import cn.iocoder.yudao.module.system.controller.admin.positionmap.vo.PositionMapSaveReqVO;
import cn.iocoder.yudao.module.system.controller.admin.robot.vo.RobotWarnMsgSaveReqVO;
import cn.iocoder.yudao.module.system.service.path.PathPlanningService;
import cn.iocoder.yudao.module.system.service.positionmap.PositionChangePointBindingService;
import cn.iocoder.yudao.module.system.service.robot.RobotTaskService;
import cn.iocoder.yudao.module.system.service.robot.RobotWarnMsgService;
import cn.iocoder.yudao.module.system.service.tool.ToolsService;
import com.alibaba.fastjson.JSON;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.MDC;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
@ -18,6 +23,7 @@ import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
import java.util.UUID;
@Slf4j
@RestController // 提供 RESTful API 接口 Feign 调用
@ -40,12 +46,11 @@ public class PathApiImpl implements PathApi {
private RobotWarnMsgService warnMsgService;
/**
* 发送初始化信息给PP
*/
@Override
@SystemRateLimiter(time = 10, count = 1, keyArg = "pathInitData",message = "路径规划初始化数据频繁")
@SystemRateLimiter(time = 10, count = 1, keyArg = "pathInitData", message = "路径规划初始化数据频繁")
public void pathInitData() {
taskExecutor.execute(() -> {
TenantContextHolder.setTenantId(1L);
@ -69,26 +74,36 @@ public class PathApiImpl implements PathApi {
/**
* PP分配任务
*
* @param message
*/
@Override
public void ppDistributionTask(String message) {
taskExecutor.execute(() -> {
TenantContextHolder.setTenantId(1L);
taskService.assignTasks(message);
// taskService.ppDistributionTask(message); 废弃了
String requestId = UUID.randomUUID().toString().replace("-", "");
MDC.put(CommonConstant.REQUEST_ID, requestId);
try {
taskService.assignTasks(message);
} finally {
MDC.clear();
}
});
}
/**
* PP处理任务失败
*
* @param message
*/
@Override
public void ppDistributionTaskFail(String message) {
TenantContextHolder.setTenantId(1L);
warnMsgService.addWarnMsg(message);
warnMsgService.sendWarnMsgToWebsocket(message);
RobotWarnMsgSaveReqVO data = JSON.parseObject(message, RobotWarnMsgSaveReqVO.class);
warnMsgService.createWarnMsg(data);
if (ObjectUtil.isNotEmpty(data.getWarnLevel()) && data.getWarnLevel() > 3) {
warnMsgService.sendWarnMsgToWebsocket(message);
}
}
@Override
@ -102,6 +117,7 @@ public class PathApiImpl implements PathApi {
/**
* 车辆即将走的点位
*
* @param message
*/
@Override
@ -112,6 +128,7 @@ public class PathApiImpl implements PathApi {
/**
* 仿真点位信息
*
* @param message
*/
@Override
@ -122,11 +139,13 @@ public class PathApiImpl implements PathApi {
/**
* 路网匹配实时数据
*
* @param message
*/
@Override
public void graphMatchData(String message) {
TenantContextHolder.setTenantId(1L);
log.info("匹配路网的消息 :{}",message);
pathPlanningService.graphMatchData(message);
}

View File

@ -142,5 +142,10 @@ public class RemoteRobotApiImpl implements RemoteRobotApi {
return robotInformationService.getMacByRobotNo(robotNo);
}
@Override
public String getRobotNoByMac(String mac) {
return robotInformationService.getRobotNoByMac(mac);
}
}

View File

@ -3,15 +3,11 @@ package cn.iocoder.yudao.module.system.api.robot;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.json.JSONUtil;
import cn.iocoder.yudao.module.system.api.robot.dto.RobotGenericsDataDTO;
import cn.iocoder.yudao.module.system.api.robot.dto.RobotStatusDataPoseDTO;
import cn.iocoder.yudao.module.system.config.ratelimiter.SystemRateLimiter;
import cn.iocoder.yudao.module.system.constant.robot.RobotTaskChcheConstant;
import cn.iocoder.yudao.module.system.util.redis.RedisUtil;
import com.alibaba.fastjson.JSON;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.RestController;
@ -26,8 +22,6 @@ public class RobotGenericsStatusApiImpl implements RobotGenericsStatusApi {
@Resource
private RedisUtil redisUtil;
@Resource@Value("${zn.robot_position_cache_time:10}")
private Long robotPositionCacheTime;
@Override
@SystemRateLimiter(time = 1, count = 20, keyArg = "updateRobotCommonStatus",message = "机器人上报车辆其他信息")
@ -36,24 +30,27 @@ public class RobotGenericsStatusApiImpl implements RobotGenericsStatusApi {
}
public void doUpdateRobotCommonStatus(RobotGenericsDataDTO robotStatusData) {
log.info("车机每3秒上报其他状态信息 :{}", JSONUtil.toJsonStr(robotStatusData));
// log.info("车机每3秒上报其他状态信息 :{}", JSONUtil.toJsonStr(robotStatusData));
if (ObjectUtil.isEmpty(robotStatusData) || ObjectUtil.isEmpty(robotStatusData.getHwStates())
|| ObjectUtil.isEmpty(robotStatusData.getMac())) {
log.info("参数不全 :{}", JSON.toJSONString(robotStatusData));
}
String mac = robotStatusData.getMac();
String pose2dKey = RobotTaskChcheConstant.ROBOT_INFORMATION_POSE_BAT_SOC +mac;
String socKey = RobotTaskChcheConstant.ROBOT_INFORMATION_SOC +mac;
Object object = redisUtil.get(pose2dKey);
RobotStatusDataPoseDTO robotStatusDataPoseDTO= JSONUtil.toBean((String)object, RobotStatusDataPoseDTO.class);
String batSoc = robotStatusData.getHwStates().getBatSoc();
if (ObjectUtil.isNotEmpty(batSoc)) {
String[] split = batSoc.split("\\.");
batSoc = split[1].substring(0,2);
robotStatusDataPoseDTO.setBatSoc(batSoc);
}
batSoc = split[1];
if (batSoc.length() > 2) {
batSoc = batSoc.substring(0,2);
}
redisUtil.set(pose2dKey,JSON.toJSONString(robotStatusDataPoseDTO),robotPositionCacheTime);
if (batSoc.startsWith("0")) {
batSoc = batSoc.substring(1);
}
redisUtil.set(socKey,batSoc);
}
}
}

View File

@ -5,6 +5,7 @@ import cn.iocoder.yudao.module.infra.api.websocket.WebSocketSenderApi;
import cn.iocoder.yudao.module.system.api.robot.dto.FloorZoneDTO;
import cn.iocoder.yudao.module.system.api.robot.dto.RobotObstaclesStatusDTO;
import cn.iocoder.yudao.module.system.api.robot.vo.RobotUpdatePalletHeightDTO;
import cn.iocoder.yudao.module.system.constant.CommonConstant;
import cn.iocoder.yudao.module.system.constant.robot.RobotTaskChcheConstant;
import cn.iocoder.yudao.module.system.constant.webSocket.WebSocketConstant;
import cn.iocoder.yudao.module.system.controller.admin.robot.vo.RobotWarnMsgSaveReqVO;
@ -51,7 +52,6 @@ public class RobotObstaclesStatusApiImpl implements RobotObstaclesStatusApi{
Object floorAreaObject = redisUtil.get(floorAreaKey);
FloorZoneDTO floorZoneDTO = JSONUtil.toBean((String) floorAreaObject, FloorZoneDTO.class);
String robotNo = robotInformationService.getRobotNoByMac(data.getMac());
RobotWarnMsgSaveReqVO warnMsg = new RobotWarnMsgSaveReqVO();
@ -61,7 +61,7 @@ public class RobotObstaclesStatusApiImpl implements RobotObstaclesStatusApi{
warnMsg.setWarnMsg(robotNo +" 机器人遇到障碍物");
warnMsgService.createWarnMsg(warnMsg);
webSocketSenderApi.sendObject(floorZoneDTO.getFloor() + "_" + floorZoneDTO.getArea(),
webSocketSenderApi.sendObject(floorZoneDTO.getFloor() + CommonConstant.SYMBOL + floorZoneDTO.getArea(),
WebSocketConstant.AGV_WARN, warnMsg.getWarnMsg());
}
}

View File

@ -1,12 +1,12 @@
package cn.iocoder.yudao.module.system.api.robot;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.json.JSONUtil;
import cn.iocoder.yudao.framework.tenant.core.context.TenantContextHolder;
import cn.iocoder.yudao.module.system.api.robot.dto.FloorZoneDTO;
import cn.iocoder.yudao.module.system.api.robot.dto.RobotStatusDataErrorDTO;
import cn.iocoder.yudao.module.system.api.robot.dto.RobotStatusDataPoseDTO;
import cn.iocoder.yudao.module.system.api.robot.vo.RobotReactiveStatusDTO;
import cn.iocoder.yudao.module.system.constant.CommonConstant;
import cn.iocoder.yudao.module.system.constant.area.FloorAreaConstant;
import cn.iocoder.yudao.module.system.constant.robot.RobotTaskChcheConstant;
import cn.iocoder.yudao.module.system.dal.dataobject.log.RobotTaskDetailActionLogDO;
import cn.iocoder.yudao.module.system.dal.dataobject.robot.RobotWarnCodeMappingDO;
@ -15,6 +15,7 @@ import cn.iocoder.yudao.module.system.dal.mysql.robot.RobotWarnCodeMappingMapper
import cn.iocoder.yudao.module.system.dal.mysql.robot.RobotWarnMsgMapper;
import cn.iocoder.yudao.module.system.enums.robot.RobotWarnType;
import cn.iocoder.yudao.module.system.enums.robot.actionlog.ActionStatusEnum;
import cn.iocoder.yudao.module.system.enums.robot.actionlog.CommandIdEnum;
import cn.iocoder.yudao.module.system.service.log.RobotTaskDetailActionLogService;
import cn.iocoder.yudao.module.system.service.robot.RobotInformationService;
import cn.iocoder.yudao.module.system.service.robot.RobotTaskDetailService;
@ -24,16 +25,12 @@ import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;
@Slf4j
@ -65,6 +62,7 @@ public class RobotReactiveStatusApiImpl implements RobotReactiveStatusApi {
@Override
public void robotReactiveStatus(String message) {
TenantContextHolder.setTenantId(1L);
// log.info("车辆所在楼层和异常信息 :{}", message);
RobotReactiveStatusDTO data = JSON.parseObject(message, RobotReactiveStatusDTO.class);
String floorAreaKey = RobotTaskChcheConstant.ROBOT_FLOOR_AREA + data.getMac();
String robotNo = robotInformationService.getRobotNoByMac(data.getMac());
@ -73,8 +71,14 @@ public class RobotReactiveStatusApiImpl implements RobotReactiveStatusApi {
FloorZoneDTO floorZone = new FloorZoneDTO();
if (ObjectUtil.isNotEmpty(o)) {
floorZone = JSON.parseObject((String) o, FloorZoneDTO.class);
String oldFloorArea = floorZone.getFloor()+"-"+floorZone.getArea();
redisUtil.hdel(oldFloorArea,robotNo);
String oldFloorArea = floorZone.getFloor() + CommonConstant.SYMBOL + floorZone.getArea();
redisUtil.hdel(oldFloorArea, robotNo);
String newFloorArea = data.getFloorZone().getFloor() + CommonConstant.SYMBOL + data.getFloorZone().getArea();
String key = FloorAreaConstant.FLOOR_AREA_ROBOT + floorZone.getFloor() + CommonConstant.SYMBOL + floorZone.getArea();
if (!oldFloorArea.equals(newFloorArea)) {
redisUtil.hdel(key, robotNo);
}
}
floorZone.setArea(data.getFloorZone().getArea());
@ -83,9 +87,12 @@ public class RobotReactiveStatusApiImpl implements RobotReactiveStatusApi {
redisUtil.set(floorAreaKey, JSON.toJSONString(floorZone));
Map<String, Object> map = new HashMap<>();
String value = floorZone.getFloor() + "-" + floorZone.getArea();
map.put(robotNo,value);
redisUtil.hmset(value,map);
String value = floorZone.getFloor() + CommonConstant.SYMBOL + floorZone.getArea();
map.put(robotNo, value);
redisUtil.hmset(value, map);
String speedKey = RobotTaskChcheConstant.ROBOT_SPEED_FORK_HEIGHT + robotNo;
redisUtil.set(speedKey, message);
// -- get 老的数据 - 看有没有 - 有的话 - 对比下 - 如果相同 - 更新hashMap中key的value
// - 如果不相同的话 - 更新当前redis数据 - 然后 - 根据老的数据 hashMapRedis 中删除 这个key的数据
@ -110,46 +117,41 @@ public class RobotReactiveStatusApiImpl implements RobotReactiveStatusApi {
private void addRobotErrorMsg(RobotReactiveStatusDTO data) {
String robotNo = robotInformationService.getRobotNoByMac(data.getMac());
List<RobotStatusDataErrorDTO> errCode = data.getErrCode();
List<String> warnCodes =
errCode.stream().map(RobotStatusDataErrorDTO::getErrorCode).collect(Collectors.toList());
Set<String> warnCodes =
errCode.stream().map(RobotStatusDataErrorDTO::getErrorCode).collect(Collectors.toSet());
List<RobotWarnCodeMappingDO> robotWarnCodeMappingDOS =
warnCodeMappingMapper.selectList(new LambdaQueryWrapper<RobotWarnCodeMappingDO>()
.in(RobotWarnCodeMappingDO::getWarnCode, warnCodes));
if (ObjectUtil.isEmpty(robotWarnCodeMappingDOS)) {
log.info("查不对应编号的告警信息 :{}", JSON.toJSONString(warnCodes));
log.info("查不对应编号的告警信息 :{}", JSON.toJSONString(data));
return;
}
Map<String, List<RobotWarnCodeMappingDO>> warnCodeMapping =
robotWarnCodeMappingDOS.stream().collect(Collectors.groupingBy(RobotWarnCodeMappingDO::getWarnCode));
Map<String, RobotWarnCodeMappingDO> warnCodeMapping =
robotWarnCodeMappingDOS.stream().collect(Collectors.toMap(RobotWarnCodeMappingDO::getWarnCode, Function.identity()));
List<RobotWarnMsgDO> warnMsgDOS = new ArrayList<>();
//机器人异常等级
String errorLevelKey = RobotTaskChcheConstant.ROBOT_ERROR_LEVEL + data.getMac();
Object errorLevel = redisUtil.get(errorLevelKey);
String errorMsgKey = RobotTaskChcheConstant.ROBOT_ERROR_MSG + data.getMac();
Object errorMsg = redisUtil.get(errorMsgKey);
Integer level = ObjectUtil.isEmpty(errorLevel) ? 0 : Integer.valueOf(errorLevel.toString());
RobotTaskDetailActionLogDO lastTaskByRobotNo = taskDetailActionLogService.getLastTaskByRobotNo(robotNo);
RobotTaskDetailActionLogDO lastTaskByRobotNo = taskDetailActionLogService.getLastTaskByRobotNo(robotNo, CommandIdEnum.TASK.getType());
int level = 0;
String msg = "";
int i = 0;
for (RobotStatusDataErrorDTO robotStatusData : errCode) {
List<RobotWarnCodeMappingDO> mappingDOS = warnCodeMapping.get(robotStatusData.getErrorCode());
RobotWarnCodeMappingDO mappingDOS = warnCodeMapping.get(robotStatusData.getErrorCode());
if (ObjectUtil.isEmpty(mappingDOS)) {
log.info("当前告警类型查不到对应的告警信息 :{}", robotStatusData.getErrorCode());
continue;
}
RobotWarnMsgDO warnMsg = RobotWarnMsgDO.builder().warnLevel(Integer.valueOf(robotStatusData.getCodeLevel()))
RobotWarnMsgDO warnMsg = RobotWarnMsgDO.builder().warnLevel(mappingDOS.getWarnLevel())
.warnCode(robotStatusData.getErrorCode())
.robotNo(robotNo)
.warnType(RobotWarnType.ROBOT_WARN.getType())
.warnMsg(robotNo + "_" + mappingDOS.get(0).getWarnMsg())
.warnSolve(mappingDOS.get(0).getWarnSolve())
.warnMsg(robotNo + CommonConstant.SYMBOL + mappingDOS.getWarnMsg())
.warnSolve(mappingDOS.getWarnSolve())
.build();
if (ObjectUtil.isNotEmpty(lastTaskByRobotNo) && ActionStatusEnum.DOING.getType().equals(lastTaskByRobotNo.getActionStatus())) {
@ -159,20 +161,16 @@ public class RobotReactiveStatusApiImpl implements RobotReactiveStatusApi {
warnMsgDOS.add(warnMsg);
if (level.intValue() < Integer.valueOf(robotStatusData.getCodeLevel()).intValue()) {
level = Integer.valueOf(robotStatusData.getCodeLevel());
errorMsg = warnMsg.getWarnMsg();
}
if (i < Integer.valueOf(robotStatusData.getCodeLevel()).intValue()) {
i = Integer.valueOf(robotStatusData.getCodeLevel());
if (level < mappingDOS.getWarnLevel()) {
level = mappingDOS.getWarnLevel();
msg = warnMsg.getWarnMsg();
}
}
redisUtil.set(errorLevelKey, level);
redisUtil.set(errorMsgKey, errorMsg);
redisUtil.set(errorMsgKey, msg);
if (ObjectUtil.isNotEmpty(lastTaskByRobotNo) && ActionStatusEnum.DOING.getType().equals(lastTaskByRobotNo.getActionStatus())
&& 4 == i && ObjectUtil.isNotEmpty(lastTaskByRobotNo.getTaskDetailId())) {
&& 4 == level && ObjectUtil.isNotEmpty(lastTaskByRobotNo.getTaskDetailId())) {
taskDetailService.setTaskDetailError(lastTaskByRobotNo.getTaskDetailId());
}

View File

@ -3,35 +3,32 @@ package cn.iocoder.yudao.module.system.api.robot;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.json.JSONUtil;
import cn.iocoder.yudao.framework.tenant.core.context.TenantContextHolder;
import cn.iocoder.yudao.module.mqtt.api.path.PathPlanningApi;
import cn.iocoder.yudao.module.mqtt.api.common.CommonApi;
import cn.iocoder.yudao.module.system.api.robot.dto.*;
import cn.iocoder.yudao.module.system.api.robot.vo.RobotInformationVO;
import cn.iocoder.yudao.module.system.api.robot.processor.RequestProcessor;
import cn.iocoder.yudao.module.system.api.robot.websocket.RobotInformationVO;
import cn.iocoder.yudao.module.system.api.robot.vo.RobotReactiveStatusDTO;
import cn.iocoder.yudao.module.system.api.robot.websocket.RobotStatusDataPoseDTO;
import cn.iocoder.yudao.module.system.config.ratelimiter.SystemRateLimiter;
import cn.iocoder.yudao.module.system.constant.CommonConstant;
import cn.iocoder.yudao.module.system.constant.area.FloorAreaConstant;
import cn.iocoder.yudao.module.system.constant.path.PathPlanningTopicConstant;
import cn.iocoder.yudao.module.system.constant.robot.RobotTaskChcheConstant;
import cn.iocoder.yudao.module.system.dal.dataobject.robot.RobotWarnCodeMappingDO;
import cn.iocoder.yudao.module.system.dal.dataobject.robot.RobotWarnMsgDO;
import cn.iocoder.yudao.module.system.dal.mysql.robot.RobotWarnCodeMappingMapper;
import cn.iocoder.yudao.module.system.dal.mysql.robot.RobotWarnMsgMapper;
import cn.iocoder.yudao.module.system.enums.robot.RobotWarnType;
import cn.iocoder.yudao.module.system.service.robot.RobotInformationService;
import cn.iocoder.yudao.module.system.service.robot.RobotWarnMsgService;
import cn.iocoder.yudao.module.system.util.redis.RedisUtil;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;
import java.util.HashMap;
import java.util.Map;
import java.util.stream.Collectors;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
@Slf4j
@RestController // 提供 RESTful API 接口 Feign 调用
@ -50,11 +47,10 @@ public class RobotStatusApiImpl implements RobotStatusApi {
@Resource
private RequestProcessor processor;
@Resource
private PathPlanningApi pathPlanningApi;
private static final ExecutorService executorService = Executors.newFixedThreadPool(5);
@Autowired
private ThreadPoolTaskExecutor taskExecutor;
@Resource
private CommonApi commonApi;
/**
* 更新机器人点位/异常/能否做任务
@ -63,13 +59,16 @@ public class RobotStatusApiImpl implements RobotStatusApi {
* @return
*/
@Override
@SystemRateLimiter(time = 1, count = 150, keyArg = "robotStatusUpdate",message = "机器人上报点位超过限流")
@SystemRateLimiter(time = 1, count = 150, keyArg = "robotStatusUpdate", message = "机器人上报点位超过限流")
public void robotStatusUpdate(RobotPoseStatusDTO robotStatusDataDTO) {
updateRobotPosed(robotStatusDataDTO);
executorService.execute(() -> {
updateRobotPosed(robotStatusDataDTO);
});
}
/**
* 更新点位信息
*
* @param robotStatusDataDTO
*/
private void updateRobotPosed(RobotPoseStatusDTO robotStatusDataDTO) {
@ -82,18 +81,32 @@ public class RobotStatusApiImpl implements RobotStatusApi {
Object floorAreaObject = redisUtil.get(floorAreaKey);
FloorZoneDTO floorZoneDTO = JSONUtil.toBean((String) floorAreaObject, FloorZoneDTO.class);
String robotNo = robotInformationService.getRobotNoByMac(robotStatusDataDTO.getMac());
String pose2dKey = RobotTaskChcheConstant.ROBOT_INFORMATION_POSE_BAT_SOC + robotStatusDataDTO.getMac();
String pose2dKey = RobotTaskChcheConstant.ROBOT_INFORMATION_POSE_BAT + robotStatusDataDTO.getMac();
Object object = redisUtil.get(pose2dKey);
RobotStatusDataPoseDTO robotStatusDataPoseDTO = JSONUtil.toBean((String) object, RobotStatusDataPoseDTO.class);
if (ObjectUtil.isNotEmpty(robotStatusDataDTO.getPose2d())) {
robotStatusDataPoseDTO.setX(robotStatusDataDTO.getPose2d().getX());
robotStatusDataPoseDTO.setY(robotStatusDataDTO.getPose2d().getY());
robotStatusDataPoseDTO.setYaw(robotStatusDataDTO.getPose2d().getYaw());
if (robotStatusDataDTO.getPose2d().getYaw().length()>7) {
String yaw = robotStatusDataDTO.getPose2d().getYaw().substring(0, 7);
robotStatusDataPoseDTO.setYaw(yaw);
}else {
robotStatusDataPoseDTO.setYaw(robotStatusDataDTO.getPose2d().getYaw());
}
}
robotStatusDataPoseDTO.setRobotNo(robotNo);
robotStatusDataPoseDTO.setFloor(floorZoneDTO.getFloor());
robotStatusDataPoseDTO.setArea(floorZoneDTO.getArea());
String speedKey = RobotTaskChcheConstant.ROBOT_SPEED_FORK_HEIGHT + robotNo;
Object speedObject = redisUtil.get(speedKey);
if (ObjectUtil.isNotEmpty(speedObject)) {
RobotReactiveStatusDTO data = JSON.parseObject(speedObject.toString(), RobotReactiveStatusDTO.class);
robotStatusDataPoseDTO.setForkHeight(data.getForkHeight());
}
redisUtil.set(pose2dKey, JSON.toJSONString(robotStatusDataPoseDTO), robotPositionCacheTime);
//机器人身上是否有货
@ -110,15 +123,18 @@ public class RobotStatusApiImpl implements RobotStatusApi {
}
robotInformationVO.setPose2d(robotStatusDataPoseDTO);
Map<String, Object> map = new HashMap<>();
String value = FloorAreaConstant.FLOOR_AREA_ROBOT + floorZoneDTO.getFloor() + CommonConstant.SYMBOL + floorZoneDTO.getArea();
map.put(robotStatusDataDTO.getMac(), JSON.toJSONString(robotInformationVO));
redisUtil.hmset(value, map, 20);
// 合并请求 - 这里接受到的数据都丢给 RequestProcessor - 再整合数据通过WebSocket丢给前端
processor.handleRequest(floorZoneDTO.getFloor() + "_" + floorZoneDTO.getArea(),
processor.handleRequest(floorZoneDTO.getFloor() + CommonConstant.SYMBOL + floorZoneDTO.getArea(),
robotStatusDataDTO.getMac(), JSONUtil.toJsonStr(robotInformationVO));
sendToPP(robotStatusDataPoseDTO);
}
private void sendToPP(RobotStatusDataPoseDTO robotStatusDataPoseDTO) {
taskExecutor.execute(()->{
pathPlanningApi.synchronousLineObject(robotStatusDataPoseDTO, PathPlanningTopicConstant.AGV_POSE);
});
commonApi.commonMethod(robotStatusDataPoseDTO, PathPlanningTopicConstant.AGV_POSE);
}
}

View File

@ -1,16 +1,26 @@
package cn.iocoder.yudao.module.system.api.robot;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.json.JSONUtil;
import cn.iocoder.yudao.framework.common.util.date.DateUtils;
import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
import cn.iocoder.yudao.framework.tenant.core.context.TenantContextHolder;
import cn.iocoder.yudao.module.infra.api.websocket.WebSocketSenderApi;
import cn.iocoder.yudao.module.mqtt.api.common.CommonApi;
import cn.iocoder.yudao.module.system.api.path.vo.RobotClosePathPlantingDTO;
import cn.iocoder.yudao.module.system.api.robot.dto.FloorZoneDTO;
import cn.iocoder.yudao.module.system.api.robot.dto.RobotCommandStateDTO;
import cn.iocoder.yudao.module.system.api.robot.dto.RobotCompleteTaskDTO;
import cn.iocoder.yudao.module.system.api.robot.websocket.RobotSkuInfoDTO;
import cn.iocoder.yudao.module.system.api.robot.websocket.WsWareHouseLocationDTO;
import cn.iocoder.yudao.module.system.constant.CommonConstant;
import cn.iocoder.yudao.module.system.constant.area.FloorAreaConstant;
import cn.iocoder.yudao.module.system.constant.path.PathPlanningChcheConstant;
import cn.iocoder.yudao.module.system.constant.path.PathPlanningTopicConstant;
import cn.iocoder.yudao.module.system.constant.robot.RobotExecutionStateConstant;
import cn.iocoder.yudao.module.system.constant.robot.RobotTaskChcheConstant;
import cn.iocoder.yudao.module.system.constant.webSocket.WebSocketConstant;
import cn.iocoder.yudao.module.system.controller.admin.log.vo.RobotTaskDetailActionLogSaveReqVO;
import cn.iocoder.yudao.module.system.dal.dataobject.log.RobotTaskDetailActionLogDO;
import cn.iocoder.yudao.module.system.dal.dataobject.houselocation.WareHouseLocationDO;
import cn.iocoder.yudao.module.system.dal.dataobject.robot.*;
@ -26,14 +36,12 @@ import cn.iocoder.yudao.module.system.enums.robot.actionlog.ActionStatusEnum;
import cn.iocoder.yudao.module.system.enums.robot.charge.ChargeTaskStatusEnum;
import cn.iocoder.yudao.module.system.enums.robot.task.RobotStatusCodeEnum;
import cn.iocoder.yudao.module.system.enums.robot.task.RobotTaskStageEnum;
import cn.iocoder.yudao.module.system.enums.wait.WaitStatusEnum;
import cn.iocoder.yudao.module.system.service.information.DeviceInformationService;
import cn.iocoder.yudao.module.system.service.log.RobotTaskDetailActionLogService;
import cn.iocoder.yudao.module.system.service.path.PathPlanningService;
import cn.iocoder.yudao.module.system.service.robot.RobotInformationService;
import cn.iocoder.yudao.module.system.service.robot.RobotTaskDetailService;
import cn.iocoder.yudao.module.system.service.robot.RobotWarnMsgService;
import cn.iocoder.yudao.module.system.service.wait.MoveToWaitService;
import cn.iocoder.yudao.module.system.util.redis.RedisUtil;
import com.alibaba.fastjson.JSON;
import lombok.extern.slf4j.Slf4j;
@ -50,6 +58,8 @@ import java.time.LocalDateTime;
import java.util.List;
import java.util.UUID;
import static cn.iocoder.yudao.module.system.service.robot.RobotInformationServiceImpl.key;
@Slf4j
@RestController // 提供 RESTful API 接口 Feign 调用
@Validated
@ -92,6 +102,9 @@ public class RobotTaskStatusApiImpl implements RobotTaskStatusApi {
@Resource
private CommonApi commonApi;
@Resource
public WebSocketSenderApi webSocketSenderApi;
@Resource
private RobotTaskDetailService taskDetailService;
@ -101,9 +114,6 @@ public class RobotTaskStatusApiImpl implements RobotTaskStatusApi {
@Resource
private RobotWarnMsgService warnMsgService;
@Resource
private MoveToWaitService moveToWaitService;
@Resource
private PathPlanningService pathPlanningService;
@ -113,6 +123,9 @@ public class RobotTaskStatusApiImpl implements RobotTaskStatusApi {
@Value("${zn.robot_doing_action.doing_action_cache_time:2*24*60*60}")
private Long doingActionCacheTime;
@Value("${zn.is_simulation:false}")
private Boolean isSimulation;
@Transactional(rollbackFor = Exception.class)
public void doRobotDoneTask(RobotCompleteTaskDTO robotCompleteTaskDTO) {
log.info("机器人完成任务上报 :{}", JSON.toJSONString(robotCompleteTaskDTO));
@ -138,6 +151,10 @@ public class RobotTaskStatusApiImpl implements RobotTaskStatusApi {
} else if (RobotExecutionStateConstant.DONE.equals(robotCompleteTaskDTO.getExecutionState())) {
robotTaskDone(robotCompleteTaskDTO);
redisUtil.del(robotDoingActionKey);
String robotNo = robotInformationService.getRobotNoByMac(robotCompleteTaskDTO.getMac());
String freeTimeKey = RobotTaskChcheConstant.ROBOT_LAST_FREE_TIME + robotNo;
String timeStr = DateUtils.getYearMonthDayHourMinuteSecon();
redisUtil.set(freeTimeKey, timeStr);
} else if (RobotExecutionStateConstant.DOING.equals(robotCompleteTaskDTO.getExecutionState())) {
robotTaskDoing(robotCompleteTaskDTO, robotDoingActionKey);
}
@ -156,27 +173,8 @@ public class RobotTaskStatusApiImpl implements RobotTaskStatusApi {
* @param robotCompleteTaskDTO
*/
private void robotTaskDoing(RobotCompleteTaskDTO robotCompleteTaskDTO, String robotDoingActionKey) {
String robotNo = robotInformationService.getRobotNoByMac(robotCompleteTaskDTO.getMac());
RobotTaskDetailActionLogDO lastLog = setLastLogDone(robotCompleteTaskDTO.getOrderId());
if (PathTaskTypeEnum.AUTO_CHARGE.getType().equals(robotCompleteTaskDTO.getOrderType())) {
chargeDoing(robotCompleteTaskDTO, robotDoingActionKey, lastLog);
} else if (PathTaskTypeEnum.MOVE_TO_WAIT.getType().equals(robotCompleteTaskDTO.getOrderType())) {
RobotTaskDetailActionLogDO logOne = new RobotTaskDetailActionLogDO();
logOne.setActionMsg("车辆正在前往等待点");
logOne.setRobotNo(robotNo);
logOne.setStartTime(LocalDateTime.now());
logOne.setTaskDetailId(robotCompleteTaskDTO.getOrderId());
if (ObjectUtil.isNotEmpty(lastLog)) {
logOne.setCommandType(lastLog.getCommandType());
logOne.setTaskNo(lastLog.getTaskNo());
}
taskDetailActionLogMapper.insert(logOne);
redisUtil.set(robotDoingActionKey, logOne.getActionMsg(), doingActionCacheTime);
moveToWaitService.updateWaitStatus(robotCompleteTaskDTO.getOrderId(), WaitStatusEnum.GO_TO_WAIT.getType());
} else {
taskDoing(robotCompleteTaskDTO, robotDoingActionKey);
}
taskDoing(robotCompleteTaskDTO, robotDoingActionKey);
if ((PathTaskTypeEnum.AUTO_CHARGE.getType().equals(robotCompleteTaskDTO.getOrderType())
|| PathTaskTypeEnum.CHARGE.getType().equals(robotCompleteTaskDTO.getOrderType()))
@ -193,6 +191,11 @@ public class RobotTaskStatusApiImpl implements RobotTaskStatusApi {
taskDetailActionLogMapper.updateActionStatus(robotCompleteTaskDTO.getOrderId(), ActionStatusEnum.DOING.getType()
, null);
if (PathTaskTypeEnum.AUTO_CHARGE.getType().equals(robotCompleteTaskDTO.getOrderType())
|| PathTaskTypeEnum.CHARGE.getType().equals(robotCompleteTaskDTO.getOrderType()) ) {
chargeDoing(robotCompleteTaskDTO);
}
}
/**
@ -218,9 +221,24 @@ public class RobotTaskStatusApiImpl implements RobotTaskStatusApi {
*/
private void robotTaskDone(RobotCompleteTaskDTO robotCompleteTaskDTO) {
setLastLogDone(robotCompleteTaskDTO.getOrderId());
//释放库位数据
if (PathTaskTypeEnum.TAKE.getType().equals(robotCompleteTaskDTO.getOrderType())
|| (PathTaskTypeEnum.TAKE_RELEASE.getType().equals(robotCompleteTaskDTO.getOrderType())
&& CommandTypeEnum.WORK_PICK_UP_GOODS.getType().equals(robotCompleteTaskDTO.getCommandStatus().getCommandType()))) {
releaseFromLocationAndSetRobotSkuInfo(robotCompleteTaskDTO);
} else if (PathTaskTypeEnum.RELEASE.getType().equals(robotCompleteTaskDTO.getOrderType())
|| PathTaskTypeEnum.TAKE_RELEASE.getType().equals(robotCompleteTaskDTO.getOrderType())) {
releaseToLocation(robotCompleteTaskDTO);
redisUtil.del(RobotTaskChcheConstant.ROBOT_TASK_SKU_INFO + robotCompleteTaskDTO.getMac());
} else {
redisUtil.del(RobotTaskChcheConstant.ROBOT_TASK_SKU_INFO + robotCompleteTaskDTO.getMac());
}
//todo 后面考虑下充电车机目前对充电的逻辑未定义
if (PathTaskTypeEnum.MOVE.getType().equals(robotCompleteTaskDTO.getOrderType())
|| PathTaskTypeEnum.MOVE_TO_WAIT_STOP.getType().equals(robotCompleteTaskDTO.getOrderType())
|| PathTaskTypeEnum.MOVE_TO_POINT.getType().equals(robotCompleteTaskDTO.getOrderType())
|| PathTaskTypeEnum.MOVE_TO_WAIT.getType().equals(robotCompleteTaskDTO.getOrderType())
|| PathTaskTypeEnum.TAKE.getType().equals(robotCompleteTaskDTO.getOrderType())
|| PathTaskTypeEnum.CHARGE.getType().equals(robotCompleteTaskDTO.getOrderType())
|| PathTaskTypeEnum.RELEASE.getType().equals(robotCompleteTaskDTO.getOrderType())) {
@ -238,17 +256,114 @@ public class RobotTaskStatusApiImpl implements RobotTaskStatusApi {
} else if (CommandTypeEnum.WORK_DROP_OFF_GOODS.getType().equals(robotCompleteTaskDTO.getCommandStatus().getCommandType())) {
taskDone(robotCompleteTaskDTO);
}
} else if (PathTaskTypeEnum.MOVE_TO_WAIT.getType().equals(robotCompleteTaskDTO.getOrderType())) {
moveToWaitService.updateWaitStatus(robotCompleteTaskDTO.getOrderId(), WaitStatusEnum.REACH_WAIT.getType());
} else if (PathTaskTypeEnum.AUTO_CHARGE.getType().equals(robotCompleteTaskDTO.getOrderType())) {
RobotChargeLogDO build = RobotChargeLogDO
.builder()
.id(robotCompleteTaskDTO.getOrderId())
.taskStatus(ChargeTaskStatusEnum.CHARGEING.getType())
.build();
chargeLogMapper.updateById(build);
}
if (PathTaskTypeEnum.AUTO_CHARGE.getType().equals(robotCompleteTaskDTO.getOrderType())
|| PathTaskTypeEnum.CHARGE.getType().equals(robotCompleteTaskDTO.getOrderType())) {
chargeLogMapper.updateChargStatusByTaskId(robotCompleteTaskDTO.getOrderId(),ChargeTaskStatusEnum.DONE.getType());
}
taskDetailActionLogMapper.updateActionStatus(robotCompleteTaskDTO.getOrderId(), ActionStatusEnum.DONE.getType(), LocalDateTime.now());
}
/**
* 释放放货库位
*
* @param robotCompleteTaskDTO
*/
private void releaseToLocation(RobotCompleteTaskDTO robotCompleteTaskDTO) {
RobotTaskDetailDO robotTaskDetailDO = robotTaskDetailMapper.selectById(robotCompleteTaskDTO.getOrderId());
if (ObjectUtil.isEmpty(robotTaskDetailDO) || ObjectUtil.isEmpty(robotTaskDetailDO.getToLocationId())) {
return;
}
WareHouseLocationDO toWareHouseLocation = locationMapper.selectById(robotTaskDetailDO.getToLocationId());
if (ObjectUtil.isEmpty(toWareHouseLocation)) {
return;
}
//查询最近一起取货任务
WareHouseLocationDO fromWareHouseLocation = getFromLocation(robotTaskDetailDO);
if (ObjectUtil.isNotEmpty(fromWareHouseLocation)) {
toWareHouseLocation.setSkuNumber(fromWareHouseLocation.getSkuNumber());
toWareHouseLocation.setSkuInfo(fromWareHouseLocation.getSkuInfo());
}
toWareHouseLocation.setLocationLock(LocationLockEnum.YES.getType());
toWareHouseLocation.setLocationUseStatus(LocationUseStatusEnum.YES.getType());
locationMapper.updateById(toWareHouseLocation);
pushWareLocation(toWareHouseLocation,robotCompleteTaskDTO.getMac(),ZeroOneEnum.ONE.getType());
}
/**
* 查询最近一次取货任务
*
* @param robotTaskDetailDO
* @return
*/
private WareHouseLocationDO getFromLocation(RobotTaskDetailDO robotTaskDetailDO) {
if (RobotTaskTypeEnum.TAKE_RELEASE.getType().equals(robotTaskDetailDO.getTaskType())
&& ObjectUtil.isNotEmpty(robotTaskDetailDO.getFromLocationId())) {
return locationMapper.selectById(robotTaskDetailDO.getFromLocationId());
}
List<RobotTaskDetailActionLogDO> actionLogs = taskDetailActionLogMapper.getLastTwoTask(robotTaskDetailDO.getRobotNo());
if (ObjectUtil.isEmpty(actionLogs)) {
return null;
}
for (RobotTaskDetailActionLogDO actionLog : actionLogs) {
if (!robotTaskDetailDO.getId().equals(actionLog.getTaskDetailId())) {
RobotTaskDetailDO taskDetail = robotTaskDetailMapper.selectById(actionLog.getTaskDetailId());
if (ObjectUtil.isEmpty(taskDetail) || !RobotTaskTypeEnum.TAKE.getType().equals(taskDetail.getTaskType())
|| ObjectUtil.isEmpty(taskDetail.getFromLocationId())) {
continue;
}
locationMapper.selectById(taskDetail.getFromLocationId());
}
}
return null;
}
/**
* 设置车辆上的物料信息释放取货库位
*
* @param robotCompleteTaskDTO
*/
private void releaseFromLocationAndSetRobotSkuInfo(RobotCompleteTaskDTO robotCompleteTaskDTO) {
RobotTaskDetailDO robotTaskDetailDO = robotTaskDetailMapper.selectById(robotCompleteTaskDTO.getOrderId());
if (ObjectUtil.isEmpty(robotTaskDetailDO) || ObjectUtil.isEmpty(robotTaskDetailDO.getFromLocationId())) {
return;
}
WareHouseLocationDO wareHouseLocationDO = locationMapper.selectById(robotTaskDetailDO.getFromLocationId());
if (ObjectUtil.isEmpty(wareHouseLocationDO)) {
return;
}
RobotSkuInfoDTO robotSkuInfo = new RobotSkuInfoDTO();
robotSkuInfo.setHaveSku(ZeroOneEnum.ONE.getType());
robotSkuInfo.setSkuNumber(wareHouseLocationDO.getSkuNumber());
robotSkuInfo.setSkuInfo(wareHouseLocationDO.getSkuInfo());
robotSkuInfo.setLocationStorey(wareHouseLocationDO.getLocationStorey());
redisUtil.set(RobotTaskChcheConstant.ROBOT_TASK_SKU_INFO + robotCompleteTaskDTO.getMac(), JSON.toJSONString(robotSkuInfo));
wareHouseLocationDO.setSkuInfo(null);
wareHouseLocationDO.setSkuNumber(0L);
wareHouseLocationDO.setLocationLock(LocationLockEnum.YES.getType());
wareHouseLocationDO.setLocationUseStatus(LocationUseStatusEnum.NO.getType());
locationMapper.updateById(wareHouseLocationDO);
pushWareLocation(wareHouseLocationDO,robotCompleteTaskDTO.getMac(),ZeroOneEnum.ZERO.getType());
}
public void pushWareLocation(WareHouseLocationDO wareHouseLocationDO, String mac, Integer type) {
String floorAreaKey = RobotTaskChcheConstant.ROBOT_FLOOR_AREA + mac;
Object floorAreaObject = redisUtil.get(floorAreaKey);
if (ObjectUtil.isEmpty(floorAreaObject)) {
return;
}
FloorZoneDTO floorZoneDTO = JSONUtil.toBean((String) floorAreaObject, FloorZoneDTO.class);
String floorAreaStr = floorZoneDTO.getFloor() + CommonConstant.SYMBOL + floorZoneDTO.getArea();
WsWareHouseLocationDTO wsWareHouseLocation = new WsWareHouseLocationDTO();
wsWareHouseLocation.setActualLocationX(wareHouseLocationDO.getActualLocationX());
wsWareHouseLocation.setActualLocationY(wareHouseLocationDO.getActualLocationY());
wsWareHouseLocation.setType(type);
wsWareHouseLocation.setFloor(floorZoneDTO.getFloor());
wsWareHouseLocation.setArea(floorZoneDTO.getArea());
log.info("让3D推送修改库存 :{}", JSON.toJSONString(wsWareHouseLocation));
webSocketSenderApi.sendObject(floorAreaStr, WebSocketConstant.THREE_D_CHANGE_STOCK, JSON.toJSONString(wsWareHouseLocation));
}
@ -324,8 +439,7 @@ public class RobotTaskStatusApiImpl implements RobotTaskStatusApi {
String solve = "";
String taskNo = "";
if (!PathTaskTypeEnum.MOVE_TO_WAIT.getType().equals(robotCompleteTaskDTO.getOrderType())
&& !PathTaskTypeEnum.AUTO_CHARGE.getType().equals(robotCompleteTaskDTO.getOrderType())
if (!PathTaskTypeEnum.AUTO_CHARGE.getType().equals(robotCompleteTaskDTO.getOrderType())
&& ObjectUtil.isEmpty(msg)) {
taskNo = taskDetailService.getTaskNoByDetailId(robotCompleteTaskDTO.getOrderId());
solve = " 并且到任务列表关闭任务 " + taskNo;
@ -348,63 +462,26 @@ public class RobotTaskStatusApiImpl implements RobotTaskStatusApi {
warnMsgService.sendWarnMsgToWebsocket(warnMsg.getWarnMsg());
}
/**
* 关闭订单
*
* @param taskDetailId
*/
public RobotTaskDetailDO closeTaskDetail(Long taskDetailId) {
return taskDetailService.closeTaskDetail(taskDetailId);
}
/**
* 处理充电中
*
* @param robotCompleteTaskDTO
*/
private void chargeDoing(RobotCompleteTaskDTO robotCompleteTaskDTO, String robotDoingActionKey, RobotTaskDetailActionLogDO lastLog) {
RobotTaskDetailActionLogDO logOne = new RobotTaskDetailActionLogDO();
RobotCommandStateDTO commandStatus = robotCompleteTaskDTO.getCommandStatus();
Integer taskStatus = ChargeTaskStatusEnum.CHARGEING.getType();
if (ObjectUtil.isNotEmpty(commandStatus) && CommandTypeEnum.MOVE_POSES.getType().equals(commandStatus.getCommandType())) {
RobotChargeLogDO robotChargeLogDO = chargeLogMapper.selectById(robotCompleteTaskDTO.getOrderId());
logOne.setActionMsg("车辆正在前往充电点" + robotChargeLogDO.getDeviceNo());
logOne.setTaskStage(RobotTaskStageEnum.MOVE.getType());
taskStatus = ChargeTaskStatusEnum.DOING.getType();
} else if (ObjectUtil.isNotEmpty(commandStatus)) {
logOne.setActionMsg("车辆正在充电");
logOne.setTaskStage(RobotTaskStageEnum.CHARGEING.getType());
}
private void chargeDoing(RobotCompleteTaskDTO robotCompleteTaskDTO) {
//编辑地图会判断这表的状态,所以自动充电任务移动到充电点就改为完成
RobotCommandStateDTO commandStatus = robotCompleteTaskDTO.getCommandStatus();
//自动充电任务移动到充电点就改为完成
if (ObjectUtil.isNotEmpty(commandStatus) && CommandTypeEnum.MOVE_POSES.getType().equals(commandStatus.getCommandType())
&& RobotExecutionStateConstant.DONE.equals(commandStatus.getExecutionState())) {
taskDetailActionLogMapper.updateActionStatus(robotCompleteTaskDTO.getOrderId(), ActionStatusEnum.DONE.getType(), LocalDateTime.now());
setTaskDone(robotCompleteTaskDTO);
}
String robotNo = robotInformationService.getRobotNoByMac(robotCompleteTaskDTO.getMac());
logOne.setRobotNo(robotNo);
logOne.setTaskDetailId(robotCompleteTaskDTO.getOrderId());
logOne.setCommandType(lastLog.getCommandType());
logOne.setTaskNo(lastLog.getTaskNo());
logOne.setStartTime(LocalDateTime.now());
taskDetailActionLogMapper.insert(logOne);
redisUtil.set(robotDoingActionKey, logOne.getActionMsg(), doingActionCacheTime);
RobotChargeLogDO build = RobotChargeLogDO
.builder()
.id(robotCompleteTaskDTO.getOrderId())
.taskStatus(taskStatus)
.build();
chargeLogMapper.updateById(build);
chargeLogMapper.updateChargStatusByTaskId(robotCompleteTaskDTO.getOrderId(),ChargeTaskStatusEnum.CHARGEING.getType());
}
/**
* 任务完成
*
* @param robotCompleteTaskDTO
*/
private void taskDone(RobotCompleteTaskDTO robotCompleteTaskDTO) {
public RobotTaskDetailDO setTaskDone(RobotCompleteTaskDTO robotCompleteTaskDTO) {
//更新任务状态
RobotTaskDetailDO detailDO = new RobotTaskDetailDO();
detailDO.setId(robotCompleteTaskDTO.getOrderId());
@ -416,7 +493,8 @@ public class RobotTaskStatusApiImpl implements RobotTaskStatusApi {
RobotTaskDetailDO robotTaskDetailDO = robotTaskDetailMapper.selectById(robotCompleteTaskDTO.getOrderId());
List<RobotTaskDetailDO> taskDetails = robotTaskDetailMapper.queryByTaskId(robotTaskDetailDO.getRobotTaskId());
boolean done =
taskDetails.stream().noneMatch(v -> (v.getTaskStatus().equals(RobotTaskDetailStatusEnum.NEW.getType())));
taskDetails.stream().noneMatch(v -> (v.getTaskStatus().equals(RobotTaskDetailStatusEnum.NEW.getType()) ||
v.getTaskStatus().equals(RobotTaskDetailStatusEnum.DOING.getType())));
if (done) {
RobotTaskDO robotTaskDO = new RobotTaskDO();
robotTaskDO.setId(taskDetails.get(0).getRobotTaskId());
@ -425,6 +503,17 @@ public class RobotTaskStatusApiImpl implements RobotTaskStatusApi {
robotTaskMapper.updateRobot(robotTaskDO);
taskCycleMapper.deletByRobotTaskId(taskDetails.get(0).getRobotTaskId());
}
return robotTaskDetailDO;
}
/**
* 任务完成
*
* @param robotCompleteTaskDTO
*/
private void taskDone(RobotCompleteTaskDTO robotCompleteTaskDTO) {
RobotTaskDetailDO robotTaskDetailDO = setTaskDone(robotCompleteTaskDTO);
RobotInformationDO robotInformationDO = robotInformationMapper.selectOne(new LambdaQueryWrapperX<RobotInformationDO>()
.eq(RobotInformationDO::getRobotNo, robotTaskDetailDO.getRobotNo()));
@ -438,6 +527,11 @@ public class RobotTaskStatusApiImpl implements RobotTaskStatusApi {
//同步任务完成给PP
pathPlanningService.updateBehavior(String.valueOf(robotCompleteTaskDTO.getOrderId()), robotTaskDetailDO.getRobotNo()
, "", PathIsReachEnum.END_WORK.getType());
if (!isSimulation) {
String plantingKey = PathPlanningChcheConstant.PATH_PLANNING_TASK + robotCompleteTaskDTO.getOrderId();
redisUtil.del(plantingKey);
}
}
@ -457,7 +551,7 @@ public class RobotTaskStatusApiImpl implements RobotTaskStatusApi {
RobotCommandStateDTO commandStatus = robotCompleteTaskDTO.getCommandStatus();
String commandType = commandStatus.getCommandType();
RobotTaskDetailActionLogDO logOne = new RobotTaskDetailActionLogDO();
RobotTaskDetailActionLogSaveReqVO logOne = new RobotTaskDetailActionLogSaveReqVO();
if (PathTaskTypeEnum.TAKE_RELEASE.getType().equals(robotCompleteTaskDTO.getOrderType())) {
if (CommandTypeEnum.MOVE_POSES.getType().equals(commandType) && RobotTaskStageEnum.UN_START.getType().equals(taskStage)) {
logOne.setActionMsg("车辆正在前往" + robotTaskDetailDO.getFromLocationNo() + "取货");
@ -473,7 +567,8 @@ public class RobotTaskStatusApiImpl implements RobotTaskStatusApi {
robotTaskDetailDO.setTaskStage(RobotTaskStageEnum.GO_RELEASE.getType());
}
} else if (PathTaskTypeEnum.CHARGE.getType().equals(robotCompleteTaskDTO.getOrderType())) {
} else if (PathTaskTypeEnum.CHARGE.getType().equals(robotCompleteTaskDTO.getOrderType())
|| PathTaskTypeEnum.AUTO_CHARGE.getType().equals(robotCompleteTaskDTO.getOrderType())) {
RobotChargeLogDO robotChargeLogDO = chargeLogMapper.selectById(robotCompleteTaskDTO.getOrderId());
if (CommandTypeEnum.MOVE_POSES.getType().equals(commandType)) {
logOne.setActionMsg("车辆正在前往" + robotChargeLogDO.getDeviceNo() + "充电");
@ -483,7 +578,9 @@ public class RobotTaskStatusApiImpl implements RobotTaskStatusApi {
robotTaskDetailDO.setTaskStage(RobotTaskStageEnum.CHARGEING.getType());
}
} else if (PathTaskTypeEnum.MOVE.getType().equals(robotCompleteTaskDTO.getOrderType())) {
} else if (PathTaskTypeEnum.MOVE.getType().equals(robotCompleteTaskDTO.getOrderType())
|| PathTaskTypeEnum.MOVE_TO_WAIT.getType().equals(robotCompleteTaskDTO.getOrderType())
|| PathTaskTypeEnum.MOVE_TO_POINT.getType().equals(robotCompleteTaskDTO.getOrderType())) {
if (CommandTypeEnum.MOVE_POSES.getType().equals(commandType)) {
logOne.setActionMsg("车辆正在前往" + robotTaskDetailDO.getToLocationNo());
robotTaskDetailDO.setTaskStage(RobotTaskStageEnum.MOVE.getType());
@ -515,19 +612,25 @@ public class RobotTaskStatusApiImpl implements RobotTaskStatusApi {
//编辑地图会判断这表的状态,所以自动充电任务移动到充电点就改为完成
if (ObjectUtil.isNotEmpty(commandStatus) && CommandTypeEnum.MOVE_POSES.getType().equals(commandStatus.getCommandType())
&& RobotExecutionStateConstant.DONE.equals(commandStatus.getExecutionState())
&& PathTaskTypeEnum.CHARGE.getType().equals(robotCompleteTaskDTO.getOrderType())) {
&& (PathTaskTypeEnum.CHARGE.getType().equals(robotCompleteTaskDTO.getOrderType())
|| PathTaskTypeEnum.AUTO_CHARGE.getType().equals(robotCompleteTaskDTO.getOrderType()))) {
taskDetailActionLogMapper.updateActionStatus(robotCompleteTaskDTO.getOrderId(), ActionStatusEnum.DONE.getType(), LocalDateTime.now());
}
String robotNo = robotInformationService.getRobotNoByMac(robotCompleteTaskDTO.getMac());
logOne.setRobotNo(robotNo);
logOne.setOriginalRobotNo(robotNo);
logOne.setTaskDetailId(robotCompleteTaskDTO.getOrderId());
logOne.setTaskStage(robotTaskDetailDO.getTaskStage());
logOne.setCommandType(PathTaskTypeEnum.getTaskType(robotTaskDetailDO.getTaskType()));
logOne.setTaskNo(robotTask.getTaskNo());
logOne.setActionStatus(ActionStatusEnum.DOING.getType());
logOne.setStartTime(LocalDateTime.now());
taskDetailActionLogMapper.insert(logOne);
Long mapId = robotInformationService.getRobotMapIdByRobotNo(robotNo);
if (ObjectUtil.isNotEmpty(mapId)) {
logOne.setPositionMapId(mapId);
}
taskDetailActionLogService.createTaskDetailActionLog(logOne);
redisUtil.set(robotDoingActionKey, logOne.getActionMsg(), doingActionCacheTime);
robotTaskDetailMapper.updateById(robotTaskDetailDO);
}
@ -570,7 +673,6 @@ public class RobotTaskStatusApiImpl implements RobotTaskStatusApi {
public void robotDoneTask(RobotCompleteTaskDTO robotCompleteTaskDTO) {
taskExecutor.execute(() -> {
String requestId = UUID.randomUUID().toString().replace("-", "");
;
MDC.put(CommonConstant.REQUEST_ID, requestId);
try {
doRobotDoneTask(robotCompleteTaskDTO);

View File

@ -3,6 +3,7 @@ package cn.iocoder.yudao.module.system.api.robot;
import cn.hutool.core.util.ObjectUtil;
import cn.iocoder.yudao.framework.tenant.core.context.TenantContextHolder;
import cn.iocoder.yudao.module.system.api.robot.vo.RobotUpdatePalletHeightDTO;
import cn.iocoder.yudao.module.system.constant.CommonConstant;
import cn.iocoder.yudao.module.system.dal.dataobject.config.CommonConfigDO;
import cn.iocoder.yudao.module.system.dal.dataobject.houselocation.WareHouseLocationDO;
import cn.iocoder.yudao.module.system.dal.dataobject.robot.RobotTaskDetailDO;
@ -101,7 +102,7 @@ public class RobotUpdatePalletHeightApiImpl implements RobotUpdatePalletHeightAp
.warnCode(WARN_CODE)
.robotNo(robotNo)
.warnType(RobotWarnType.ROBOT_WARN.getType())
.warnMsg(data.getOrderId() + "_" + "不需要更新库位高度")
.warnMsg(data.getOrderId() + CommonConstant.SYMBOL + "不需要更新库位高度")
.build();
warnMsgMapper.insert(warnMsg);
}

View File

@ -1,7 +1,8 @@
package cn.iocoder.yudao.module.system.api.robot;
package cn.iocoder.yudao.module.system.api.robot.processor;
import cn.hutool.core.map.MapUtil;
import cn.iocoder.yudao.module.infra.api.websocket.WebSocketSenderApi;
import cn.iocoder.yudao.module.system.constant.webSocket.WebSocketConstant;
import com.alibaba.fastjson.JSON;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
@ -46,8 +47,8 @@ public class RequestProcessor {
private void sendData(String map, Map<String, String> data) {
// -- 发送给对应的websocket
// System.out.println("key:" + map + "发送数据:" + data);
log.info("key:" + map + "发送数据:" + data);
webSocketSenderApi.sendObject(map, "map_push", data);
// log.info("key:" + map + "发送数据:" + data);
webSocketSenderApi.sendObject(map, WebSocketConstant.MAP_PUSH, data);
}
public void shutdown() {

View File

@ -6,4 +6,9 @@ public class CommonConstant {
* MDC请求常亮
*/
public static final String REQUEST_ID = "requestId";
/**
* 拼接的符号 不能改
*/
public static final String SYMBOL = "_";
}

View File

@ -0,0 +1,13 @@
package cn.iocoder.yudao.module.system.constant.area;
public class FloorAreaConstant {
//楼层区域的KEY通过这个KEY可以查这个楼层下所有的机器人
//仅限给WEBSOCKET推送给前端使用缓存15秒
public static String FLOOR_AREA_ROBOT = "floor:area:robot";
//所有的楼层区域
public static String FLOOR_AREA_ALL = "floor:area:all";
}

View File

@ -9,7 +9,10 @@ public class RobotTaskChcheConstant {
public static String ROBOT_CARGO_DETECTED = "robot:information:cargo:detected";
//机器人点位和电量 (拼接的是mac地址)
public static String ROBOT_INFORMATION_POSE_BAT_SOC = "robot:information:pose:bat:soc";
public static String ROBOT_INFORMATION_POSE_BAT = "robot:information:pose:bat";
//机器人电量
public static String ROBOT_INFORMATION_SOC = "robot:information:soc";
//机器人楼层和区域 (拼接的是mac地址)
public static String ROBOT_FLOOR_AREA = "robot:floor:area";
@ -35,15 +38,15 @@ public class RobotTaskChcheConstant {
//机器人mac地址和机器人id以及机器人类型映射(通过mac地址获取机器人基本信息)
public static String ROBOT_GET_ROBOT_INFO = "robot:information:getRobotInfo";
//机器人正在做的任务整体信息(拼接common_id)
// public static String ROBOT_ACTION_LOG_ENTITY = "robot:action:log:entity";
//机器人取货完成(拼接robot_task_detail的id)
// public static String ROBOT_ACTION_TAKE_GOODS = "robot:take:";
//机器人放货完成(拼接robot_task_detail的id)
// public static String ROBOT_ACTION_RELEASE_GOODS = "robot:release:";
//机器人点位
public static String ROBOT_ADDRESS = "robot:information:address";
//机器人速度和货叉高度 (拼接的是车辆编号robotNo)
public static String ROBOT_SPEED_FORK_HEIGHT = "robot:speed:fork:height";
//机器人开始空闲的时间 (拼接的是车辆编号robotNo)
public static String ROBOT_LAST_FREE_TIME = "robot:last:free:time";
//机器人物料数量(拼接的是mac地址)
public static String ROBOT_TASK_SKU_INFO = "robot:task:sku:info";
}

View File

@ -7,4 +7,19 @@ public class WebSocketConstant {
* webSocket推送车机要走的点位id
*/
public static String PLANNING_MOVE_POSE = "planning_move_pose";
/**
* 3D地图的信息
*/
public static String THREE_D_MAP_PUSH = "3d_map_push";
/**
* 3D地图修改库存
*/
public static String THREE_D_CHANGE_STOCK = "3d_change_stock";
/**
* 推送地图点位信息
*/
public static String MAP_PUSH = "map_push";
}

View File

@ -51,6 +51,9 @@ public class AuthLoginReqVO {
@Schema(description = "state", requiredMode = Schema.RequiredMode.REQUIRED, example = "9b2ffbc1-7425-4155-9894-9d5c08541d62")
private String socialState;
@Schema(description = "登录来源地址, 远遥传: remote")
private String clientid;
/**
* 开启验证码的 Group
*/

View File

@ -6,10 +6,7 @@ import cn.iocoder.yudao.framework.common.pojo.PageParam;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils;
import cn.iocoder.yudao.module.system.controller.admin.houselocation.vo.WareHouseLocationPageReqVO;
import cn.iocoder.yudao.module.system.controller.admin.houselocation.vo.WareHouseLocationRespVO;
import cn.iocoder.yudao.module.system.controller.admin.houselocation.vo.WareHouseLocationSaveReqVO;
import cn.iocoder.yudao.module.system.controller.admin.houselocation.vo.WareHouseLocationVO;
import cn.iocoder.yudao.module.system.controller.admin.houselocation.vo.*;
import cn.iocoder.yudao.module.system.dal.dataobject.houselocation.WareHouseLocationDO;
import cn.iocoder.yudao.module.system.service.houselocation.HouseLocationService;
import io.swagger.v3.oas.annotations.Operation;
@ -123,4 +120,12 @@ public class WareHouseLocationController {
houseLocationService.updateHouseLocationList(list);
return success(true);
}
@GetMapping("/getLocationsXYByMapId")
@Operation(summary = "根据地图id查询此地图对应的所有库位,包括库位坐标")
@Parameter(name = "mapId", description = "地图id", required = true, example = "1024")
public CommonResult<List<WareHouseLocationItemRespVO>> getLocationsXYByMapId(@RequestParam("mapId") Long mapId) {
List<WareHouseLocationItemRespVO> list = houseLocationService.getLocationsXYByMapId(mapId);
return success(list);
}
}

View File

@ -0,0 +1,63 @@
package cn.iocoder.yudao.module.system.controller.admin.houselocation.vo;
import com.alibaba.excel.annotation.ExcelProperty;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import java.math.BigDecimal;
@Schema(description = "管理后台 - 库位和坐标 Response VO")
@Data
public class WareHouseLocationItemRespVO {
@Schema(description = "主键ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "31866")
private Long id;
@Schema(description = "库位编号")
private String locationNo;
@Schema(description = "物料信息")
private String skuInfo;
@Schema(description = "物料数量")
private Long skuNumber;
@Schema(description = "启用/禁用0禁用、1启用")
private Integer locationEnable;
@Schema(description = "锁定/正常0锁定、1正常")
private Integer locationLock;
@Schema(description = "状态0空闲、1占用", example = "2")
private Integer locationUseStatus;
@Schema(description = "宽度")
private BigDecimal locationWide;
@Schema(description = "长度")
private BigDecimal locationDeep;
@Schema(description = "层数")
private Integer locationStorey;
@Schema(description = "实际坐标x轴")
private String actualLocationX;
@Schema(description = "实际坐标y轴")
private String actualLocationY;
}

View File

@ -35,7 +35,7 @@ public class DeviceInformationPageReqVO extends PageParam {
@Schema(description = "深度")
private BigDecimal locationDeep;
//1:充电桩,2:输送线,3:码垛机,4:自动门,5:提升机,6:信号灯,7:按钮盒,8:拆垛机
//1:充电桩,2:输送线,3:码垛机,4:自动门,5:提升机,6:信号灯,7:按钮盒,8:拆垛机, 9:摄像头
@Schema(description = "设备类型 字典device_type", example = "2")
private Integer deviceType;
@ -74,8 +74,8 @@ public class DeviceInformationPageReqVO extends PageParam {
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
private LocalDateTime[] createTime;
@Schema(description = "设备使用状态(IDLE:空闲、USEING:使用中)")
private String deviceUseStatus;
@Schema(description = "设备使用状态(0:空闲、1:使用中)")
private Integer deviceUseStatus;
@Schema(description = "设备专有属性1自动充电类型充电桩、2手动充电类型充电桩")
private Integer deviceAttribute;
@ -89,4 +89,10 @@ public class DeviceInformationPageReqVO extends PageParam {
@Schema(description = "最后使用者")
private String lastUser;
@Schema(description = "摄像头类型1 枪机 2半球 3球机 4云台枪机")
private String cameraType;
@Schema(description = "摄像头编号")
private String cameraCode;
}

View File

@ -42,7 +42,7 @@ public class DeviceInformationRespVO {
@ExcelProperty("深度")
private BigDecimal locationDeep;
//1:充电桩,2:输送线,3:码垛机,4:自动门,5:提升机,6:信号灯,7:按钮盒,8:拆垛机
//1:充电桩,2:输送线,3:码垛机,4:自动门,5:提升机,6:信号灯,7:按钮盒,8:拆垛机, 9:摄像头
@Schema(description = "设备类型 字典device_type", requiredMode = Schema.RequiredMode.REQUIRED, example = "2")
@ExcelProperty("设备类型 字典device_type")
private Integer deviceType;
@ -91,9 +91,9 @@ public class DeviceInformationRespVO {
@ExcelProperty("创建时间")
private LocalDateTime createTime;
@Schema(description = "设备使用状态(IDLE:空闲、USEING:使用中)")
@ExcelProperty("设备使用状态(IDLE:空闲、USEING:使用中)")
private String deviceUseStatus;
@Schema(description = "设备使用状态(0:空闲、1:使用中)")
@ExcelProperty("设备使用状态(0:空闲、1:使用中)")
private Integer deviceUseStatus;
@Schema(description = "设备专有属性1自动充电类型充电桩、2手动充电类型充电桩")
@ExcelProperty("设备专有属性1自动充电类型充电桩、2手动充电类型充电桩")
@ -120,4 +120,11 @@ public class DeviceInformationRespVO {
@ExcelProperty("最后使用者")
private String lastUser;
@Schema(description = "摄像头类型1 枪机 2半球 3球机 4云台枪机")
@ExcelProperty("摄像头类型1 枪机 2半球 3球机 4云台枪机")
private String cameraType;
@Schema(description = "摄像头编号")
@ExcelProperty("摄像头编号")
private String cameraCode;
}

View File

@ -35,7 +35,7 @@ public class DeviceInformationSaveReqVO {
@Schema(description = "深度")
private BigDecimal locationDeep;
//1:充电桩,2:输送线,3:码垛机,4:自动门,5:提升机,6:信号灯,7:按钮盒,8:拆垛机
//1:充电桩,2:输送线,3:码垛机,4:自动门,5:提升机,6:信号灯,7:按钮盒,8:拆垛机 9:摄像头
@Schema(description = "设备类型 字典device_type", requiredMode = Schema.RequiredMode.REQUIRED, example = "2")
@NotNull(message = "设备类型不能为空")
private Integer deviceType;
@ -72,8 +72,8 @@ public class DeviceInformationSaveReqVO {
@Schema(description = "设备最后通讯时间")
private LocalDateTime deviceLastTime;
@Schema(description = "设备使用状态(IDLE:空闲、USEING:使用中)")
private String deviceUseStatus;
@Schema(description = "设备使用状态(0:空闲、1:使用中)")
private Integer deviceUseStatus;
@Schema(description = "设备专有属性1自动充电类型充电桩、2手动充电类型充电桩")
private Integer deviceAttribute;
@ -89,4 +89,9 @@ public class DeviceInformationSaveReqVO {
@Schema(description = "最后使用者")
private String lastUser;
@Schema(description = "摄像头类型1 枪机 2半球 3球机 4云台枪机")
private String cameraType;
@Schema(description = "摄像头编号")
private String cameraCode;
}

View File

@ -14,7 +14,7 @@ import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_
@ToString(callSuper = true)
public class RobotTaskDetailActionLogPageReqVO extends PageParam {
@Schema(description = "下发给车机的任务id", example = "18544")
@Schema(description = "-1代表是任务其他的是操作的明细", example = "18544")
private Long commandId;
@Schema(description = "下发给车机的任务类型", example = "2")
@ -51,4 +51,12 @@ public class RobotTaskDetailActionLogPageReqVO extends PageParam {
@Schema(description = "结束时间")
private LocalDateTime endTime;
@Schema(description = "车辆做任务时,所在的仓库点位地图表id")
private Long positionMapId;
@Schema(description = "是否已经统计(0:未统计、1已经统计)")
private Integer alreadyCounted;
@Schema(description = "这条任务第一次执行的AGV编号")
private String originalRobotNo;
}

View File

@ -15,8 +15,8 @@ public class RobotTaskDetailActionLogRespVO {
@ExcelProperty("主键ID")
private Long id;
@Schema(description = "下发给车机的任务id", example = "18544")
@ExcelProperty("下发给车机的任务id")
@Schema(description = "-1代表是任务其他的是操作的明细", example = "18544")
@ExcelProperty("-1代表是任务其他的是操作的明细")
private Long commandId;
@Schema(description = "下发给车机的任务类型", example = "2")
@ -61,4 +61,15 @@ public class RobotTaskDetailActionLogRespVO {
@ExcelProperty("结束时间")
private LocalDateTime endTime;
@Schema(description = "车辆做任务时,所在的仓库点位地图表id")
@ExcelProperty("车辆做任务时,所在的仓库点位地图表id")
private Long positionMapId;
@Schema(description = "是否已经统计(0:未统计、1已经统计)")
@ExcelProperty("是否已经统计(0:未统计、1已经统计)")
private Integer alreadyCounted;
@Schema(description = "这条任务第一次执行的AGV编号")
@ExcelProperty("这条任务第一次执行的AGV编号")
private String originalRobotNo;
}

View File

@ -13,7 +13,7 @@ public class RobotTaskDetailActionLogSaveReqVO {
@Schema(description = "主键ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "25503")
private Long id;
@Schema(description = "下发给车机的任务id", example = "18544")
@Schema(description = "-1代表是任务其他的是操作的明细", example = "18544")
private Long commandId;
@Schema(description = "下发给车机的任务类型", example = "2")
@ -26,7 +26,7 @@ public class RobotTaskDetailActionLogSaveReqVO {
private String actionMsg;
@Schema(description = "动作状态(0:未开始、1执行中、2已完成、3已取消、4:异常)", requiredMode = Schema.RequiredMode.REQUIRED, example = "2")
@NotNull(message = "动作状态(0:未开始、1执行中、2已完成、3已取消、4:异常)不能为空")
// @NotNull(message = "动作状态(0:未开始、1执行中、2已完成、3已取消、4:异常)不能为空") 不要了
private Integer actionStatus;
@Schema(description = "AGV编号")
@ -35,6 +35,9 @@ public class RobotTaskDetailActionLogSaveReqVO {
@Schema(description = "robot_task_detail的id")
private Long taskDetailId;
@Schema(description = "任务阶段(0:待执行、1前往取货、2取货中、3前往放货、4放货中、5结束、6移动中、7:正在充电、8:取消、9:人工完成、10:异常)")
private Long taskStage;
@Schema(description = "任务号")
private String taskNo;
@ -44,4 +47,12 @@ public class RobotTaskDetailActionLogSaveReqVO {
@Schema(description = "结束时间")
private LocalDateTime endTime;
@Schema(description = "车辆做任务时,所在的仓库点位地图表id")
private Long positionMapId;
@Schema(description = "是否已经统计(0:未统计、1已经统计)")
private Integer alreadyCounted;
@Schema(description = "这条任务第一次执行的AGV编号")
private String originalRobotNo;
}

View File

@ -22,6 +22,7 @@ import cn.iocoder.yudao.module.system.service.log.UserOperationLogService;
import cn.iocoder.yudao.module.system.service.positionmap.PositionMapItemService;
import cn.iocoder.yudao.module.system.service.positionmap.PositionMapLineService;
import cn.iocoder.yudao.module.system.service.robot.RobotTaskService;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
@ -35,6 +36,7 @@ import javax.annotation.Resource;
import javax.validation.Valid;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
@ -136,7 +138,7 @@ public class PositionMapItemController {
@PostMapping("/lineAddItem")
@Operation(summary = "线上加点保存点位")
@PreAuthorize("@ss.hasPermission('system:position-map-item:lineAddItem')")
public CommonResult<Boolean> lineAddItem(@Valid @RequestBody List<PositionMapItemNodeDTO> list) {
public CommonResult<Map<String,Object>> lineAddItem(@Valid @RequestBody List<PositionMapItemNodeDTO> list) {
PositionMapItemSaveReqVO positionMapItem = BeanUtils.toBean(list.get(0), PositionMapItemSaveReqVO.class);
positionMapItemService.createPositionMapItem(positionMapItem);
@ -144,10 +146,23 @@ public class PositionMapItemController {
positionMapLineService.deletePositionMapLine(list.get(0).getOldLineId());
List<PositionMapLineSaveReqVO> positionMapLines = list.get(0).getPositionMapLines();
List<PositionMapLineDO> lineList = BeanUtils.toBean(positionMapLines, PositionMapLineDO.class);
List<Long> itemIds = new ArrayList<>();
for (PositionMapLineDO positionMapLineDO : lineList) {
itemIds.add(positionMapLineDO.getStartingPointId());
itemIds.add(positionMapLineDO.getEndPointId());
}
Map<Long,Long> sortNumMap = positionMapItemService.getSortNumMapByIds(itemIds);
for (PositionMapLineDO positionMapLineDO : lineList) {
positionMapLineDO.setPositionMapId(positionMapItem.getPositionMapId());
positionMapLineDO.setStartingSortNum(sortNumMap.get(positionMapLineDO.getStartingPointId()).intValue());
positionMapLineDO.setEndPointSortNum(sortNumMap.get(positionMapLineDO.getEndPointId()).intValue());
}
positionMapLineService.batchSaveLines(lineList);
return success(true);
Map<String,Object> map = new HashMap<>();
map.put("ITEM",positionMapItemService.getPositionMapItem(positionMapItem.getId()));
map.put("LINE",lineList);
return success(map);
}
}

View File

@ -8,6 +8,7 @@ import lombok.EqualsAndHashCode;
import lombok.ToString;
import org.springframework.format.annotation.DateTimeFormat;
import javax.validation.constraints.NotEmpty;
import java.time.LocalDateTime;
import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
@ -52,7 +53,9 @@ public class PositionMapItemPageReqVO extends PageParam {
@Schema(description = "排序的位置,越大越优先堆放")
private Long locationNumber;
@Schema(description = "等待点使用状态(0.空闲 1.使用中)")
@Schema(description = "等待点使用状态, 0:空闲 ,1:前往停车点(预占用停车点) ,2.使用中(已经在停车位上)")
private Integer useStatus;
@Schema(description = "AGV编号")
private String robotNo;
}

View File

@ -70,8 +70,12 @@ public class PositionMapItemRespVO {
@ExcelProperty("排序的位置,越大越优先堆放")
private Long locationNumber;
@Schema(description = "等待点使用状态(0.空闲 1.使用中)")
@ExcelProperty("等待点使用状态(0.空闲 1.使用中)")
@Schema(description = "等待点使用状态, 0:空闲 ,1:前往停车点(预占用停车点) ,2.使用中(已经在停车位上)")
@ExcelProperty("等待点使用状态, 0:空闲 ,1:前往停车点(预占用停车点) ,2.使用中(已经在停车位上)")
private Integer useStatus;
@Schema(description = "AGV编号")
@ExcelProperty("等待点使用状态(0.空闲 1.使用中)")
private String robotNo;
}

View File

@ -43,6 +43,9 @@ public class PositionMapItemSaveReqVO {
@Schema(description = "排序的位置,越大越优先堆放")
private Long locationNumber;
@Schema(description = "等待点使用状态(0.空闲 1.使用中)")
@Schema(description = "等待点使用状态, 0:空闲 ,1:前往停车点(预占用停车点) ,2.使用中(已经在停车位上)")
private Integer useStatus;
@Schema(description = "AGV编号")
private String robotNo;
}

View File

@ -121,4 +121,13 @@ public class RobotTaskController {
return success(pageResult);
}
@PostMapping("/checkHaveTask")
@Operation(summary = "判断是否存在任务")
@PreAuthorize("@ss.hasPermission('robot:task:checkHaveTask')")
public CommonResult<Boolean> checkHaveTask() {
//校验是否存在未完成的任务
taskService.checkHaveDoingTask();
return success(true);
}
}

View File

@ -4,6 +4,7 @@ import cn.iocoder.yudao.module.system.controller.admin.robot.vo.RobotTaskDetailP
import cn.iocoder.yudao.module.system.controller.admin.robot.vo.RobotTaskDetailRespVO;
import cn.iocoder.yudao.module.system.controller.admin.robot.vo.RobotTaskDetailSaveReqVO;
import cn.iocoder.yudao.module.system.dal.dataobject.robot.RobotTaskDetailDO;
import cn.iocoder.yudao.module.system.enums.robot.task.RobotTaskManualInterventionEnum;
import cn.iocoder.yudao.module.system.service.robot.RobotTaskDetailService;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
@ -96,7 +97,7 @@ public class RobotTaskDetailController {
@Operation(summary = "人工完成")
@PreAuthorize("@ss.hasPermission('robot:task-detail:manuallyCompleted')")
public CommonResult manuallyCompleted(@RequestParam("id") Long id) {
taskDetailService.manuallyCompleted(id,"人工完成");
taskDetailService.manuallyCompleted(id,"人工完成", RobotTaskManualInterventionEnum.RCS_DONE.getType());
return success(true);
}

View File

@ -1,5 +1,7 @@
package cn.iocoder.yudao.module.system.controller.admin.robot.camera;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.*;
import java.util.*;
@ -13,6 +15,7 @@ import com.alibaba.excel.annotation.*;
public class RobotCameraRespVO {
@Schema(description = "主键ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "30856")
@JsonSerialize(using = ToStringSerializer.class)
@ExcelProperty("主键ID")
private Long id;

View File

@ -1,5 +1,7 @@
package cn.iocoder.yudao.module.system.controller.admin.robot.chargelog;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.*;
import java.util.*;
@ -14,6 +16,7 @@ public class RobotChargeLogRespVO {
@Schema(description = "主键ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "6554")
@ExcelProperty("主键ID")
@JsonSerialize(using = ToStringSerializer.class)
private Long id;
@Schema(description = "AGV编号")

View File

@ -1,6 +1,8 @@
package cn.iocoder.yudao.module.system.controller.admin.robot.detail;
import com.alibaba.excel.annotation.ExcelProperty;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
@ -9,6 +11,7 @@ import java.time.LocalDateTime;
@Data
public class RobotTaskDetailLogResoVO {
@Schema(description = "主键ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "26224")
@JsonSerialize(using = ToStringSerializer.class)
private Long id;
@Schema(description = "任务号")

View File

@ -1,5 +1,7 @@
package cn.iocoder.yudao.module.system.controller.admin.robot.mapstop;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.*;
import java.util.*;
@ -14,6 +16,7 @@ public class RobotMapStopRespVO {
@Schema(description = "主键ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "1220")
@ExcelProperty("主键ID")
@JsonSerialize(using = ToStringSerializer.class)
private Long id;
@Schema(description = "急停仓库点位地图表id", example = "20550")

View File

@ -2,10 +2,11 @@ package cn.iocoder.yudao.module.system.controller.admin.robot.vo;
import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
import com.alibaba.excel.annotation.ExcelProperty;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import javax.validation.constraints.NotNull;
import java.util.Set;
@ -14,6 +15,7 @@ import java.util.Set;
@ExcelIgnoreUnannotated
public class RobotInformationPageRespVO {
@Schema(description = "主键ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "21881")
@JsonSerialize(using = ToStringSerializer.class)
@ExcelProperty("主键ID")
private Long id;

View File

@ -3,6 +3,8 @@ package cn.iocoder.yudao.module.system.controller.admin.robot.vo;
import cn.iocoder.yudao.framework.mybatis.core.type.LongListTypeHandler;
import cn.iocoder.yudao.module.system.controller.admin.robot.camera.RobotCameraAddVO;
import com.baomidou.mybatisplus.annotation.TableField;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.*;
import java.time.LocalDateTime;
@ -17,6 +19,7 @@ public class RobotInformationRespVO {
@Schema(description = "主键ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "21881")
@ExcelProperty("主键ID")
@JsonSerialize(using = ToStringSerializer.class)
private Long id;
@Schema(description = "车辆类型表id", example = "28234")

View File

@ -1,6 +1,8 @@
package cn.iocoder.yudao.module.system.controller.admin.robot.vo;
import cn.iocoder.yudao.module.system.controller.admin.robot.camera.RobotCameraAddVO;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import org.hibernate.validator.constraints.Range;
@ -16,6 +18,7 @@ import java.util.Set;
public class RobotInformationSaveReqVO {
@Schema(description = "主键ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "21881")
@JsonSerialize(using = ToStringSerializer.class)
private Long id;
@Schema(description = "车辆类型表id", example = "28234")

View File

@ -2,6 +2,8 @@ package cn.iocoder.yudao.module.system.controller.admin.robot.vo;
import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
import com.alibaba.excel.annotation.ExcelProperty;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
@ -14,6 +16,7 @@ public class RobotModelRespVO {
@Schema(description = "主键ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "15571")
@ExcelProperty("主键ID")
@JsonSerialize(using = ToStringSerializer.class)
private Long id;
@Schema(description = "车辆类型", requiredMode = Schema.RequiredMode.REQUIRED)

View File

@ -1,5 +1,7 @@
package cn.iocoder.yudao.module.system.controller.admin.robot.vo;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.*;
import java.util.*;
@ -14,6 +16,7 @@ public class RobotTaskAutoMoveRespVO {
@Schema(description = "主键ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "30110")
@ExcelProperty("主键ID")
@JsonSerialize(using = ToStringSerializer.class)
private Long id;
@Schema(description = "机器人任务主表id", example = "24553")

View File

@ -9,6 +9,7 @@ import javax.validation.constraints.NotNull;
@Data
@Schema(description = "子列表")
public class RobotTaskDetailAddVO {
private Long id;
@Schema(description = "任务类型1取放货、2停车、 3充电、4移动、5仅取货、6仅放货、7扫描码、8检测托盘类型、9:移动到点位)", requiredMode = Schema.RequiredMode.REQUIRED, example = "2")
@NotNull(message = "任务类型1取放货、2停车、 3充电、4移动、5仅取货、6仅放货、7扫描码、8检测托盘类型、9:移动到点位)不能为空")
private Integer taskType;

View File

@ -96,4 +96,10 @@ public class RobotTaskDetailPageReqVO extends PageParam {
@Schema(description = "是否发生异常(0:正常、1异常)")
private Integer occurError;
@Schema(description = "是否人工干预(0:未干预、1RCS关闭、2RCS人工完成、3远遥取货完成、4远遥任务完成、5远遥取货完成和远遥任务完成)")
private Integer manualIntervention;
@Schema(description = "人工干预时间")
private LocalDateTime manualInterventionTime;
}

View File

@ -1,5 +1,7 @@
package cn.iocoder.yudao.module.system.controller.admin.robot.vo;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.*;
@ -13,6 +15,7 @@ public class RobotTaskDetailRespVO {
@Schema(description = "主键ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "26224")
@ExcelProperty("主键ID")
@JsonSerialize(using = ToStringSerializer.class)
private Long id;
@Schema(description = "机器人任务主表id", requiredMode = Schema.RequiredMode.REQUIRED, example = "9241")
@ -118,4 +121,10 @@ public class RobotTaskDetailRespVO {
@Schema(description = "是否发生异常(0:正常、1异常)")
private Integer occurError;
@Schema(description = "是否人工干预(0:未干预、1RCS关闭、2RCS人工完成、3远遥取货完成、4远遥任务完成、5远遥取货完成和远遥任务完成)")
private Integer manualIntervention;
@Schema(description = "人工干预时间")
private LocalDateTime manualInterventionTime;
}

View File

@ -97,4 +97,10 @@ public class RobotTaskDetailSaveReqVO {
@Schema(description = "是否发生异常(0:正常、1异常)")
private Integer occurError;
@Schema(description = "是否人工干预(0:未干预、1RCS关闭、2RCS人工完成、3远遥取货完成、4远遥任务完成、5远遥取货完成和远遥任务完成)")
private Integer manualIntervention;
@Schema(description = "人工干预时间")
private LocalDateTime manualInterventionTime;
}

View File

@ -1,6 +1,8 @@
package cn.iocoder.yudao.module.system.controller.admin.robot.vo;
import cn.iocoder.yudao.module.system.dal.dataobject.robot.RobotTaskDetailDO;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.*;
import java.util.*;
@ -17,6 +19,7 @@ public class RobotTaskRespVO {
@Schema(description = "主键ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "15306")
@ExcelProperty("主键ID")
@JsonSerialize(using = ToStringSerializer.class)
private Long id;
@Schema(description = "是否拼接任务0不拼接、1拼接", requiredMode = Schema.RequiredMode.REQUIRED)

View File

@ -1,5 +1,7 @@
package cn.iocoder.yudao.module.system.controller.admin.robot.vo;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.*;
import java.util.*;
@ -14,6 +16,7 @@ public class RobotWarnCodeMappingRespVO {
@Schema(description = "主键ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "15754")
@ExcelProperty("主键ID")
@JsonSerialize(using = ToStringSerializer.class)
private Long id;
@Schema(description = "告警等级 (1,2,3,4)")

View File

@ -1,5 +1,7 @@
package cn.iocoder.yudao.module.system.controller.admin.robot.vo;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.*;
import java.util.*;
@ -14,6 +16,7 @@ public class RobotWarnMsgRespVO {
@Schema(description = "主键ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "26180")
@ExcelProperty("主键ID")
@JsonSerialize(using = ToStringSerializer.class)
private Long id;
@Schema(description = "AGV编号")

View File

@ -0,0 +1,95 @@
package cn.iocoder.yudao.module.system.controller.admin.statistics;
import cn.iocoder.yudao.module.system.controller.admin.statistics.vo.*;
import cn.iocoder.yudao.module.system.dal.dataobject.statistics.RobotWorkingHoursStatisticsDO;
import cn.iocoder.yudao.module.system.service.statistics.RobotWorkingHoursStatisticsService;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import org.springframework.validation.annotation.Validated;
import org.springframework.security.access.prepost.PreAuthorize;
import io.swagger.v3.oas.annotations.tags.Tag;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.Operation;
import javax.validation.constraints.*;
import javax.validation.*;
import javax.servlet.http.*;
import java.util.*;
import java.io.IOException;
import cn.iocoder.yudao.framework.common.pojo.PageParam;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils;
import cn.iocoder.yudao.framework.apilog.core.annotation.ApiAccessLog;
import static cn.iocoder.yudao.framework.apilog.core.enums.OperateTypeEnum.*;
@Tag(name = "管理后台 - 车辆工作时长统计")
@RestController
@RequestMapping("/system/statistics/robot-working-hours-statistics")
@Validated
public class RobotWorkingHoursStatisticsController {
@Resource
private RobotWorkingHoursStatisticsService robotWorkingHoursStatisticsService;
@PostMapping("/create")
@Operation(summary = "创建车辆工作时长统计")
@PreAuthorize("@ss.hasPermission('statistics:robot-working-hours-statistics:create')")
public CommonResult<Long> createRobotWorkingHoursStatistics(@Valid @RequestBody RobotWorkingHoursStatisticsSaveReqVO createReqVO) {
return success(robotWorkingHoursStatisticsService.createRobotWorkingHoursStatistics(createReqVO));
}
@PutMapping("/update")
@Operation(summary = "更新车辆工作时长统计")
@PreAuthorize("@ss.hasPermission('statistics:robot-working-hours-statistics:update')")
public CommonResult<Boolean> updateRobotWorkingHoursStatistics(@Valid @RequestBody RobotWorkingHoursStatisticsSaveReqVO updateReqVO) {
robotWorkingHoursStatisticsService.updateRobotWorkingHoursStatistics(updateReqVO);
return success(true);
}
@DeleteMapping("/delete")
@Operation(summary = "删除车辆工作时长统计")
@Parameter(name = "id", description = "编号", required = true)
@PreAuthorize("@ss.hasPermission('statistics:robot-working-hours-statistics:delete')")
public CommonResult<Boolean> deleteRobotWorkingHoursStatistics(@RequestParam("id") Long id) {
robotWorkingHoursStatisticsService.deleteRobotWorkingHoursStatistics(id);
return success(true);
}
@GetMapping("/get")
@Operation(summary = "获得车辆工作时长统计")
@Parameter(name = "id", description = "编号", required = true, example = "1024")
@PreAuthorize("@ss.hasPermission('statistics:robot-working-hours-statistics:query')")
public CommonResult<RobotWorkingHoursStatisticsRespVO> getRobotWorkingHoursStatistics(@RequestParam("id") Long id) {
RobotWorkingHoursStatisticsDO robotWorkingHoursStatistics = robotWorkingHoursStatisticsService.getRobotWorkingHoursStatistics(id);
return success(BeanUtils.toBean(robotWorkingHoursStatistics, RobotWorkingHoursStatisticsRespVO.class));
}
@GetMapping("/page")
@Operation(summary = "获得车辆工作时长统计分页")
@PreAuthorize("@ss.hasPermission('statistics:robot-working-hours-statistics:query')")
public CommonResult<PageResult<RobotWorkingHoursStatisticsRespVO>> getRobotWorkingHoursStatisticsPage(@Valid RobotWorkingHoursStatisticsPageReqVO pageReqVO) {
PageResult<RobotWorkingHoursStatisticsDO> pageResult = robotWorkingHoursStatisticsService.getRobotWorkingHoursStatisticsPage(pageReqVO);
return success(BeanUtils.toBean(pageResult, RobotWorkingHoursStatisticsRespVO.class));
}
@GetMapping("/export-excel")
@Operation(summary = "导出车辆工作时长统计 Excel")
@PreAuthorize("@ss.hasPermission('statistics:robot-working-hours-statistics:export')")
@ApiAccessLog(operateType = EXPORT)
public void exportRobotWorkingHoursStatisticsExcel(@Valid RobotWorkingHoursStatisticsPageReqVO pageReqVO,
HttpServletResponse response) throws IOException {
pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE);
List<RobotWorkingHoursStatisticsDO> list = robotWorkingHoursStatisticsService.getRobotWorkingHoursStatisticsPage(pageReqVO).getList();
// 导出 Excel
ExcelUtils.write(response, "车辆工作时长统计.xls", "数据", RobotWorkingHoursStatisticsRespVO.class,
BeanUtils.toBean(list, RobotWorkingHoursStatisticsRespVO.class));
}
}

View File

@ -0,0 +1,72 @@
package cn.iocoder.yudao.module.system.controller.admin.statistics;
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.module.system.controller.admin.statistics.dto.RobotStatusClassificationDTO;
import cn.iocoder.yudao.module.system.controller.admin.statistics.dto.RobotTaskManualInterventionDTO;
import cn.iocoder.yudao.module.system.controller.admin.statistics.dto.RobotWarnMsgClassificationDTO;
import cn.iocoder.yudao.module.system.controller.admin.statistics.dto.RobotWorkHourStatisticsDTO;
import cn.iocoder.yudao.module.system.service.robot.RobotInformationService;
import cn.iocoder.yudao.module.system.service.robot.RobotTaskDetailService;
import cn.iocoder.yudao.module.system.service.robot.RobotWarnMsgService;
import cn.iocoder.yudao.module.system.service.statistics.RobotWorkingHoursStatisticsService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import java.util.List;
import java.util.Map;
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
@Tag(name = "管理后台 - 统计")
@RestController
@RequestMapping("/system/statistics")
@Validated
public class StatisticsController {
@Resource
private RobotInformationService informationService;
@Resource
private RobotTaskDetailService taskDetailService;
@Resource
private RobotWarnMsgService warnMsgService;
@Resource
private RobotWorkingHoursStatisticsService robotWorkingHoursStatisticsService;
@GetMapping("/robotStatusClassification")
@Operation(summary = "统计车辆状态分类")
@PreAuthorize("@ss.hasPermission('robot:information:robotStatusClassification')")
public CommonResult<RobotStatusClassificationDTO> robotStatusClassification() {
return success(informationService.robotStatusClassification());
}
@GetMapping("/robotTaskAutomaticArtificial")
@Operation(summary = "统计任务人工完成/自动完成" ,description = "type 1:周, 2:月, 3:季度")
@PreAuthorize("@ss.hasPermission('robot:information:robotTaskAutomaticArtificial')")
public CommonResult<RobotTaskManualInterventionDTO> robotTaskAutomaticArtificial(@RequestParam("type") String type) {
return success(taskDetailService.robotTaskAutomaticArtificial(type));
}
@GetMapping("/robotWarnMsgClassification")
@Operation(summary = "统计故障根因分析" ,description = "type 1:周, 2:月, 3:季度")
@PreAuthorize("@ss.hasPermission('robot:information:robotWarnMsgClassification')")
public CommonResult<Map<String,List<RobotWarnMsgClassificationDTO>>> robotWarnMsgClassification(@RequestParam("type") String type) {
return success(warnMsgService.robotWarnMsgClassification(type));
}
@GetMapping("/robotWorkHourStatistics")
@Operation(summary = "车辆工作时长统计" ,description = "type 1:周, 2:月, 3:季度 ; positionMapId 地图Id")
@PreAuthorize("@ss.hasPermission('robot:information:robotWorkHourStatistics')")
public CommonResult<List<RobotWorkHourStatisticsDTO>> robotWorkHourStatistics(@RequestParam("type") String type,
@RequestParam("positionMapId") String positionMapId) {
return success(robotWorkingHoursStatisticsService.robotWorkHourStatistics(type,positionMapId));
}
}

View File

@ -0,0 +1,35 @@
package cn.iocoder.yudao.module.system.controller.admin.statistics.dto;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Builder;
import lombok.Data;
@Data
@Builder
public class RobotStatusClassificationDTO {
@Schema(description = "空闲车辆百分比")
private Integer idle ;
@Schema(description = "空闲车辆数量")
private Integer idleNum = 0;
@Schema(description = "执行任务车辆百分比")
private Integer doingTask;
@Schema(description = "执行任务车辆数量")
private Integer doingTaskNum = 0;
@Schema(description = "充电车辆百分比")
private Integer charge ;
@Schema(description = "充电车辆数量")
private Integer chargeNum = 0;
@Schema(description = "故障车辆百分比")
private Integer fault;
@Schema(description = "故障车辆数量")
private Integer faultNum = 0;
}

View File

@ -0,0 +1,21 @@
package cn.iocoder.yudao.module.system.controller.admin.statistics.dto;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
@Data
public class RobotTaskManualInterventionDTO {
@Schema(description = "人工完成任务的百分比")
private Integer artificialDone = 0;
@Schema(description = "人工完成任务的数量")
private Integer artificialDoneNum = 0;
@Schema(description = "自动完成任务的百分比")
private Integer automaticDone = 0;
@Schema(description = "自动完成任务的数量")
private Integer automaticDoneNum = 0;
}

View File

@ -0,0 +1,17 @@
package cn.iocoder.yudao.module.system.controller.admin.statistics.dto;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
@Data
public class RobotWarnMsgClassificationDTO {
@Schema(description = "时间")
private String warnTime;
@Schema(description = "告警等级, 1,23,4")
private String warnLevel;
@Schema(description = "数量")
private Integer num;
}

View File

@ -0,0 +1,20 @@
package cn.iocoder.yudao.module.system.controller.admin.statistics.dto;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
@Data
public class RobotWorkHourStatisticsDTO {
@Schema(description = "车辆编号", example = "28478")
private String robotNo;
@Schema(description = "空闲时长 单位小时", example = "28478")
private String freeTimeNum;
@Schema(description = "工作时长 单位小时", example = "28478")
private String taskTimeNum;
@Schema(description = "充电时长 单位小时", example = "28478")
private String chargeTimeNum;
}

View File

@ -0,0 +1,34 @@
package cn.iocoder.yudao.module.system.controller.admin.statistics.vo;
import lombok.*;
import java.util.*;
import io.swagger.v3.oas.annotations.media.Schema;
import cn.iocoder.yudao.framework.common.pojo.PageParam;
import org.springframework.format.annotation.DateTimeFormat;
import java.time.LocalDateTime;
import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
@Schema(description = "管理后台 - 车辆工作时长统计分页 Request VO")
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
public class RobotWorkingHoursStatisticsPageReqVO extends PageParam {
@Schema(description = "仓库点位地图表id", example = "28478")
private Long positionMapId;
@Schema(description = "AGV编号")
private String robotNo;
@Schema(description = "时长,单位分钟")
private Long duration;
@Schema(description = "类型(0:空闲时长, 1:任务时长, 2:充电时长)", example = "1")
private Integer durationType;
@Schema(description = "创建时间")
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
private LocalDateTime[] createTime;
}

Some files were not shown because too many files have changed in this diff Show More