Compare commits
12 Commits
fix/wcs-ou
...
89b2fff3d1
| Author | SHA1 | Date | |
|---|---|---|---|
| 89b2fff3d1 | |||
| 72b88ed0e3 | |||
|
|
d98fe2a30c | ||
|
|
af308d7dc9 | ||
|
|
ad9f8d87fd | ||
|
|
fa9386773f | ||
|
|
cafcde4a35 | ||
|
|
24eaaa2823 | ||
|
|
24fb696a67 | ||
|
|
9b008f5fe7 | ||
|
|
03e30d1db0 | ||
|
|
9c6c32b7ed |
@@ -83,12 +83,6 @@
|
|||||||
<artifactId>slf4j-api</artifactId>
|
<artifactId>slf4j-api</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.springframework.boot</groupId>
|
|
||||||
<artifactId>spring-boot-starter-test</artifactId>
|
|
||||||
<scope>test</scope>
|
|
||||||
</dependency>
|
|
||||||
|
|
||||||
<!-- plc连接库 -->
|
<!-- plc连接库 -->
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.apache.plc4x</groupId>
|
<groupId>org.apache.plc4x</groupId>
|
||||||
@@ -112,11 +106,6 @@
|
|||||||
|
|
||||||
<build>
|
<build>
|
||||||
<plugins>
|
<plugins>
|
||||||
<plugin>
|
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
|
||||||
<artifactId>maven-surefire-plugin</artifactId>
|
|
||||||
<version>3.2.5</version>
|
|
||||||
</plugin>
|
|
||||||
<plugin>
|
<plugin>
|
||||||
<groupId>org.springframework.boot</groupId>
|
<groupId>org.springframework.boot</groupId>
|
||||||
<artifactId>spring-boot-maven-plugin</artifactId>
|
<artifactId>spring-boot-maven-plugin</artifactId>
|
||||||
|
|||||||
@@ -0,0 +1,30 @@
|
|||||||
|
package com.ruoyi.algorithm.controller;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.security.access.prepost.PreAuthorize;
|
||||||
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
|
import org.springframework.web.bind.annotation.PutMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RequestBody;
|
||||||
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
import com.ruoyi.algorithm.service.ITidyService;
|
||||||
|
import com.ruoyi.common.core.domain.AjaxResult;
|
||||||
|
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/algorithm/tidy")
|
||||||
|
public class TidyController {
|
||||||
|
@Autowired
|
||||||
|
private ITidyService tidyService;
|
||||||
|
|
||||||
|
@PreAuthorize("@ss.hasPermi('algorithm:tidy:query')")
|
||||||
|
@GetMapping("/status")
|
||||||
|
public AjaxResult status() { return AjaxResult.success(tidyService.getStatus()); }
|
||||||
|
|
||||||
|
@PreAuthorize("@ss.hasPermi('algorithm:tidy:edit')")
|
||||||
|
@PutMapping("/mode")
|
||||||
|
public AjaxResult mode(@RequestBody Map<String, String> body) {
|
||||||
|
try { return AjaxResult.success(tidyService.updateMode(body == null ? null : body.get("mode"))); }
|
||||||
|
catch (IllegalArgumentException ex) { return AjaxResult.error(ex.getMessage()); }
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
package com.ruoyi.algorithm.service;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
public interface ITidyService {
|
||||||
|
Map<String, Object> getStatus();
|
||||||
|
Map<String, Object> updateMode(String mode);
|
||||||
|
}
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
package com.ruoyi.algorithm.service.impl;
|
||||||
|
|
||||||
|
import java.util.LinkedHashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.concurrent.atomic.AtomicReference;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
import com.ruoyi.algorithm.service.ITidyService;
|
||||||
|
|
||||||
|
@Service
|
||||||
|
public class TidyServiceImpl implements ITidyService {
|
||||||
|
private final AtomicReference<String> mode = new AtomicReference<>("AUTO");
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Map<String, Object> getStatus() {
|
||||||
|
Map<String, Object> result = new LinkedHashMap<>();
|
||||||
|
result.put("mode", mode.get());
|
||||||
|
result.put("enabled", true);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Map<String, Object> updateMode(String requestedMode) {
|
||||||
|
if (requestedMode == null || !("AUTO".equalsIgnoreCase(requestedMode) || "MANUAL".equalsIgnoreCase(requestedMode))) {
|
||||||
|
throw new IllegalArgumentException("mode must be AUTO or MANUAL");
|
||||||
|
}
|
||||||
|
mode.set(requestedMode.toUpperCase());
|
||||||
|
return getStatus();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -53,6 +53,12 @@ public class Wcs2WmsController {
|
|||||||
return apiService.cancelMydoJob(jobParam);
|
return apiService.cancelMydoJob(jobParam);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Return a read-only snapshot of all S-RGV vehicles. */
|
||||||
|
@PostMapping("/tidyVehicleSnapshot")
|
||||||
|
public AjaxResult tidyVehicleSnapshot() {
|
||||||
|
return apiService.tidyVehicleSnapshot();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -14,143 +14,187 @@ import java.util.UUID;
|
|||||||
@Data
|
@Data
|
||||||
public class GenAgvSchedulingTaskRequest {
|
public class GenAgvSchedulingTaskRequest {
|
||||||
/**
|
/**
|
||||||
* 请求编号
|
* 起始站点
|
||||||
* 同一个请求重复提交, 使用同一编号
|
|
||||||
*/
|
*/
|
||||||
@NotNull
|
private String FromStation;
|
||||||
private String reqCode = UUID.randomUUID().toString();
|
|
||||||
/**
|
/**
|
||||||
* 请求时间
|
* 目的站点
|
||||||
* 格式: “yyyy-MM-dd HH:mm:ss”
|
|
||||||
*/
|
*/
|
||||||
private String reqTime = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
|
private String ToStation;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 客户端编号
|
* 任务类型(以实际的任务类型为准)
|
||||||
* 客户端编号,如PDA,HCWMS等
|
|
||||||
*/
|
*/
|
||||||
private String clientCode;
|
private String Type;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 令牌号
|
* 类名
|
||||||
* 由调度系统颁发
|
|
||||||
*/
|
*/
|
||||||
private String tokenCode;
|
private String ClassName;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 任务类型
|
* 任务引导ID
|
||||||
* 内置任务类型:
|
|
||||||
* 厂内货架搬运: F01
|
|
||||||
* 厂内货架空满交换: F02
|
|
||||||
* 辊筒搬运接驳:F03
|
|
||||||
* 厂内货架出库AGV待命:F04
|
|
||||||
* 旋转货架: F05
|
|
||||||
* 厂内电梯任务: F06
|
|
||||||
* 以下为叉车专用任务类型
|
|
||||||
* 高位货架到工作台: F11
|
|
||||||
* 工作台到高位货架: F12
|
|
||||||
* 巷道到工作台: F13
|
|
||||||
* 工作台到巷道: F14
|
|
||||||
* 高位货架到工作台(接驳) : F15
|
|
||||||
* 工作台到高位货架 (接驳) : F16
|
|
||||||
* 巷道到工作台(接驳) : F17
|
|
||||||
* 工作台到巷道(接驳) : F18
|
|
||||||
* 叉车电梯主任务: F20
|
|
||||||
*/
|
*/
|
||||||
@NotNull
|
private String TaskGuideId;
|
||||||
private String taskTyp;
|
|
||||||
/**
|
/**
|
||||||
* 容器类型(叉车/CTU专用) 叉车项目必传
|
* 订单 ID
|
||||||
*/
|
*/
|
||||||
private String ctnrTyp;
|
private String OrderId;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 容器编号 (叉车/CTU专用)
|
* 触发ID
|
||||||
*/
|
*/
|
||||||
private String ctnrCode; //
|
private String TriggerId;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 容器数量(叉车堆叠专用),默认值1,仅记录堆叠的数量不记录堆叠的每个容器号
|
* 扩展字段4
|
||||||
*/
|
*/
|
||||||
private String ctnrNum;
|
private String Extend4;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 任务模式
|
* 扩展字段5
|
||||||
* 0-普通move 1-出库move 2-入库move 3-移库move
|
|
||||||
*/
|
*/
|
||||||
private String taskMode;
|
private String Extend5;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 工作位
|
* 扩展字段6
|
||||||
* 与RCS-2000端配置的位置名称一致, 工作位名称为字母\数字\或组合
|
|
||||||
*/
|
*/
|
||||||
private String wbCode;
|
private String Extend6;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 位置路径
|
* 扩展字段7
|
||||||
* AGV关键路径位置集合,与任务类型中模板配置的位置路径一一对应。待现场地图部署、配置完成后可获取
|
|
||||||
*/
|
*/
|
||||||
private List<PositionCodeData> positionCodePath;
|
private String Extend7;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 货架编号
|
* 扩展字段8
|
||||||
* 不指定货架可以为空
|
|
||||||
*/
|
*/
|
||||||
private String podCode;
|
private String Extend8;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 货架方向
|
* 扩展字段9
|
||||||
* “180”,”0”,”90”,”-90” 分别对应地图的”左”,”右”,”上”,”下”
|
|
||||||
* 不指定方向可以为空
|
|
||||||
* 如果终点不是工作台或工作台未配置操作方向则货架拣货方向podDir作为终点方向
|
|
||||||
* 如果工作台配有操作方向,则系统会根据货架拣货方向podDir和工作台操作方向计算货架终点方向
|
|
||||||
*/
|
*/
|
||||||
private String podDir;
|
private String Extend9;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 货架类型, 传空时表示随机找个货架
|
* 任务附加信息
|
||||||
* 找空货架传参方式如下:
|
|
||||||
* -1: 代表不关心货架类型, 找到空货架即可.
|
|
||||||
* -2: 代表从工作位获取关联货架类型, 如果未配置, 只找空货架.
|
|
||||||
* 货架类型编号: 只找该货架类型的空货架
|
|
||||||
*/
|
*/
|
||||||
private String podTyp;
|
private TaskAdditionallInfo TaskAdditionallInfo;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 物料批次
|
* 任务附加信息类
|
||||||
* 物料批次或货架上的物料唯一编码,生成任务单时,货架与物料直接绑定时使用. (通过同时传podCode和materialLot来绑定或通过 wbCode 找到位置上的货架和materialLot来绑定)
|
|
||||||
* 如果是区域/策略内查找货架,可以匹配对应物料批次的货架,支持以下值:
|
|
||||||
* 0:区域/策略内查找空货架
|
|
||||||
* 1:区域/策略内查找满货架
|
|
||||||
* 其他值:查找指定物料批次对应的货架
|
|
||||||
* 巷道任务通过该字段传入特征值
|
|
||||||
*/
|
*/
|
||||||
private String materialLot;
|
@Data
|
||||||
/**
|
public static class TaskAdditionallInfo {
|
||||||
* 优先级
|
/**
|
||||||
* 从(1~127)级,最大优先级最高。为空时,采用任务模板的优先级
|
* 任务ID
|
||||||
*/
|
*/
|
||||||
private String priority;
|
private String TaskId;
|
||||||
/**
|
|
||||||
* AGV编号
|
/**
|
||||||
* 填写表示指定某一编号的AGV执行该任务
|
* 库存ID
|
||||||
*/
|
*/
|
||||||
private String agvCode;
|
private String StockId;
|
||||||
/**
|
|
||||||
* 任务单号
|
/**
|
||||||
* 选填, 不填系统自动生成
|
* 任务引导ID
|
||||||
*/
|
*/
|
||||||
private String taskCode;
|
private String TaskGuideId;
|
||||||
/**
|
|
||||||
* 组编号
|
/**
|
||||||
* CTU场景下用于按组出库,同组任务优先拼车。 如业务需要任务组间或组内按顺序出库,则需调用料箱顺序出库(CTU)接口。
|
* 触发ID
|
||||||
* 潜伏式场景下,通过组号来管理顺序出库的顺序,组号小的优先出库。
|
*/
|
||||||
*/
|
private String TriggerId;
|
||||||
private String groupId;
|
|
||||||
/**
|
/**
|
||||||
* 设备类型
|
* 下一任务添加阶段
|
||||||
*/
|
*/
|
||||||
private String agvTyp;
|
private String NextTaskAddStage;
|
||||||
/**
|
|
||||||
* 选择策略
|
/**
|
||||||
* 区域/策略中挑选货架以及根据物料批次挑选货架时的先进先出规则,支持以下4个值:
|
* 链ID
|
||||||
* 1:按照货架到达储位的时间顺序,先进先出
|
*/
|
||||||
* 2:按照货架到达储位的时间顺序,先进后出
|
private String ChainId;
|
||||||
* 9:按照货架绑定物料批次的时间顺序,先进先出
|
|
||||||
* 10:按照货架绑定物料批次的时间顺序,先进后出
|
/**
|
||||||
*/
|
* 链类型
|
||||||
private String positionSelStrategy;
|
*/
|
||||||
/**
|
private Integer ChainType;
|
||||||
* 自定义数据
|
|
||||||
*/
|
/**
|
||||||
private String data;
|
* 链排序
|
||||||
|
*/
|
||||||
|
private Integer ChainSort;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 图号
|
||||||
|
*/
|
||||||
|
private String FigureNo;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 尺寸
|
||||||
|
*/
|
||||||
|
private String Size;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 箱号
|
||||||
|
*/
|
||||||
|
private String BoxNo;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 物料
|
||||||
|
*/
|
||||||
|
private String Mater;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 相关数量
|
||||||
|
*/
|
||||||
|
private Integer RelatedCount;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 序列号
|
||||||
|
*/
|
||||||
|
private String SerialNo;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 重量
|
||||||
|
*/
|
||||||
|
private String Weight;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 站点号
|
||||||
|
*/
|
||||||
|
private String StationNo;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 手动计数
|
||||||
|
*/
|
||||||
|
private String HandCount;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 批次
|
||||||
|
*/
|
||||||
|
private String Batch;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 前置相关任务ID
|
||||||
|
*/
|
||||||
|
private String PreviousRelatedTaskId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 下一相关任务ID
|
||||||
|
*/
|
||||||
|
private String NextRelatedTaskId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 级联任务开始
|
||||||
|
*/
|
||||||
|
private String CascadeTaskBeginning;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 级联任务结束
|
||||||
|
*/
|
||||||
|
private String CascadeTaskEnding;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,23 @@
|
|||||||
|
package com.ruoyi.api.domain.wcs2wms;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
/** Read-only vehicle status snapshot exposed to WMS. */
|
||||||
|
@Data
|
||||||
|
public class SrgvVehicleSnapshot {
|
||||||
|
private String guid;
|
||||||
|
private Integer deviceId;
|
||||||
|
private String deviceName;
|
||||||
|
private String agvStatus;
|
||||||
|
private Boolean online;
|
||||||
|
private Boolean healthy;
|
||||||
|
private Boolean idle;
|
||||||
|
private Integer taskNo;
|
||||||
|
private Integer alarm;
|
||||||
|
private Integer errMsg;
|
||||||
|
private Integer chargeFlag;
|
||||||
|
private Integer locked;
|
||||||
|
private Integer battery;
|
||||||
|
private String currSite;
|
||||||
|
private Integer currFloor;
|
||||||
|
}
|
||||||
@@ -150,4 +150,6 @@ public interface IApiService
|
|||||||
AjaxResult insertAgvQuene(HashMap<String, Object> objectObjectHashMap);
|
AjaxResult insertAgvQuene(HashMap<String, Object> objectObjectHashMap);
|
||||||
|
|
||||||
void finishAgvJob(String container);
|
void finishAgvJob(String container);
|
||||||
|
|
||||||
|
AjaxResult tidyVehicleSnapshot();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -68,6 +68,8 @@ public interface IRequestLogService
|
|||||||
*/
|
*/
|
||||||
public RequestLog getRequestLog(String url, String param, String endPoint);
|
public RequestLog getRequestLog(String url, String param, String endPoint);
|
||||||
|
|
||||||
|
public RequestLog getRequestLogAgv(String url, String endPoint, String param);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 接收请求,并插入日志
|
* 接收请求,并插入日志
|
||||||
* @param url
|
* @param url
|
||||||
|
|||||||
@@ -17,8 +17,10 @@ import com.ruoyi.api.domain.agv.genAgvSchedulingTask.GenAgvSchedulingTaskRespons
|
|||||||
import com.ruoyi.api.domain.agv.genAgvSchedulingTask.PositionCodeData;
|
import com.ruoyi.api.domain.agv.genAgvSchedulingTask.PositionCodeData;
|
||||||
import com.ruoyi.api.domain.wcs2wms.JobParam;
|
import com.ruoyi.api.domain.wcs2wms.JobParam;
|
||||||
import com.ruoyi.api.domain.wcs2wms.ReceiveJob;
|
import com.ruoyi.api.domain.wcs2wms.ReceiveJob;
|
||||||
|
import com.ruoyi.api.domain.wcs2wms.SrgvVehicleSnapshot;
|
||||||
|
import com.ruoyi.device.srgv.domain.DeviceSrgv;
|
||||||
|
import com.ruoyi.device.srgv.mapper.DeviceSrgvMapper;
|
||||||
import com.ruoyi.api.service.IApiService;
|
import com.ruoyi.api.service.IApiService;
|
||||||
import com.ruoyi.bas.cargospace.mapper.BasCargoSpaceMapper;
|
|
||||||
import com.ruoyi.common.core.domain.AjaxResult;
|
import com.ruoyi.common.core.domain.AjaxResult;
|
||||||
import com.ruoyi.common.utils.DateUtils;
|
import com.ruoyi.common.utils.DateUtils;
|
||||||
import com.ruoyi.job.domain.MydoJob;
|
import com.ruoyi.job.domain.MydoJob;
|
||||||
@@ -55,9 +57,9 @@ public class ApiServiceImpl implements IApiService {
|
|||||||
@Autowired
|
@Autowired
|
||||||
private IMydoJobService mydoJobService;
|
private IMydoJobService mydoJobService;
|
||||||
@Autowired
|
@Autowired
|
||||||
private BasCargoSpaceMapper basCargoSpaceMapper;
|
|
||||||
@Autowired
|
|
||||||
private IAgvContainerTaskService agvContainerTaskService;
|
private IAgvContainerTaskService agvContainerTaskService;
|
||||||
|
@Autowired
|
||||||
|
private DeviceSrgvMapper deviceSrgvMapper;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -362,20 +364,6 @@ public class ApiServiceImpl implements IApiService {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public AjaxResult receiveOutMydoJob(ReceiveJob receiveOutJob) {
|
public AjaxResult receiveOutMydoJob(ReceiveJob receiveOutJob) {
|
||||||
Integer jobType = parseOutboundJobType(receiveOutJob);
|
|
||||||
if (jobType == null || jobType < 20) {
|
|
||||||
String rawType = receiveOutJob == null ? null : receiveOutJob.getInOrOut();
|
|
||||||
return AjaxResult.error("WCS 无法识别作业类型 " + rawType + ",任务未接收");
|
|
||||||
}
|
|
||||||
if (jobType != 30) {
|
|
||||||
String cargoSpaceId = receiveOutJob.getCargoSpaceId();
|
|
||||||
if (basCargoSpaceMapper.selectBasCargoSpaceByCargoSpaceId(cargoSpaceId) == null) {
|
|
||||||
return AjaxResult.error("WCS 未找到出库货位 " + cargoSpaceId + ",任务未接收");
|
|
||||||
}
|
|
||||||
if (basCargoSpaceMapper.countOutboundBlockingPositions(cargoSpaceId) > 0) {
|
|
||||||
return AjaxResult.error("同通道外侧货位尚未清空,等待前置移库完成");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
MydoJob mydoJob = new MydoJob();
|
MydoJob mydoJob = new MydoJob();
|
||||||
mydoJob.setJobId(receiveOutJob.getJobId());
|
mydoJob.setJobId(receiveOutJob.getJobId());
|
||||||
mydoJob.setTaskNo(receiveOutJob.getTaskNo());
|
mydoJob.setTaskNo(receiveOutJob.getTaskNo());
|
||||||
@@ -399,17 +387,6 @@ public class ApiServiceImpl implements IApiService {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private Integer parseOutboundJobType(ReceiveJob job) {
|
|
||||||
if (job == null || job.getInOrOut() == null) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
return Integer.valueOf(job.getInOrOut());
|
|
||||||
} catch (NumberFormatException ignored) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public AjaxResult receiveInMydoJob(ReceiveJob receiveInJob) {
|
public AjaxResult receiveInMydoJob(ReceiveJob receiveInJob) {
|
||||||
MydoJob mydoJob = new MydoJob();
|
MydoJob mydoJob = new MydoJob();
|
||||||
@@ -541,4 +518,38 @@ public class ApiServiceImpl implements IApiService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public AjaxResult tidyVehicleSnapshot() {
|
||||||
|
List<DeviceSrgv> vehicles = deviceSrgvMapper.selectDeviceSrgvList(new DeviceSrgv());
|
||||||
|
List<SrgvVehicleSnapshot> snapshots = new ArrayList<>();
|
||||||
|
for (DeviceSrgv vehicle : vehicles) {
|
||||||
|
boolean online = "1".equals(vehicle.getAgvStatus());
|
||||||
|
boolean healthy = online && value(vehicle.getAlarm()) <= 1 && value(vehicle.getErrMsg()) == 0;
|
||||||
|
boolean idle = healthy && value(vehicle.getTaskNo()) == 0
|
||||||
|
&& value(vehicle.getLocked()) == 0 && value(vehicle.getChargeFlag()) == 0;
|
||||||
|
SrgvVehicleSnapshot snapshot = new SrgvVehicleSnapshot();
|
||||||
|
snapshot.setGuid(vehicle.getGuid());
|
||||||
|
snapshot.setDeviceId(vehicle.getDeviceId());
|
||||||
|
snapshot.setDeviceName(vehicle.getDeviceName());
|
||||||
|
snapshot.setAgvStatus(vehicle.getAgvStatus());
|
||||||
|
snapshot.setOnline(online);
|
||||||
|
snapshot.setHealthy(healthy);
|
||||||
|
snapshot.setIdle(idle);
|
||||||
|
snapshot.setTaskNo(vehicle.getTaskNo());
|
||||||
|
snapshot.setAlarm(vehicle.getAlarm());
|
||||||
|
snapshot.setErrMsg(vehicle.getErrMsg());
|
||||||
|
snapshot.setChargeFlag(vehicle.getChargeFlag());
|
||||||
|
snapshot.setLocked(vehicle.getLocked());
|
||||||
|
snapshot.setBattery(vehicle.getBattery());
|
||||||
|
snapshot.setCurrSite(vehicle.getCurrSite());
|
||||||
|
snapshot.setCurrFloor(vehicle.getCurrFloor());
|
||||||
|
snapshots.add(snapshot);
|
||||||
|
}
|
||||||
|
return AjaxResult.success(snapshots);
|
||||||
|
}
|
||||||
|
|
||||||
|
private int value(Integer number) {
|
||||||
|
return number == null ? 0 : number;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,11 +20,6 @@ public interface BasCargoSpaceMapper
|
|||||||
*/
|
*/
|
||||||
public BasCargoSpace selectBasCargoSpaceByCargoSpaceId(String cargoSpaceId);
|
public BasCargoSpace selectBasCargoSpaceByCargoSpaceId(String cargoSpaceId);
|
||||||
|
|
||||||
/**
|
|
||||||
* Count occupied positions or unfinished outbound jobs outside the requested position.
|
|
||||||
*/
|
|
||||||
int countOutboundBlockingPositions(@Param("cargoSpaceId") String cargoSpaceId);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 查询库存信息列表
|
* 查询库存信息列表
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -67,6 +67,8 @@ public interface AgvQueueMapper
|
|||||||
*/
|
*/
|
||||||
AgvQueue selectAgvQueueByTaskCode(String taskCode);
|
AgvQueue selectAgvQueueByTaskCode(String taskCode);
|
||||||
|
|
||||||
|
AgvQueue selectAgvQueueByStatus();
|
||||||
|
|
||||||
void insertHistory(String reqCode);
|
void insertHistory(String reqCode);
|
||||||
|
|
||||||
void selectKx(HashMap<String, Object> map);
|
void selectKx(HashMap<String, Object> map);
|
||||||
|
|||||||
@@ -67,6 +67,8 @@ public interface IAgvQueueService
|
|||||||
*/
|
*/
|
||||||
AgvQueue selectAgvQueueByTaskCode(String taskCode);
|
AgvQueue selectAgvQueueByTaskCode(String taskCode);
|
||||||
|
|
||||||
|
AgvQueue selectAgvQueueByStatus();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 插入agv完成历史
|
* 插入agv完成历史
|
||||||
* @param reqCode
|
* @param reqCode
|
||||||
|
|||||||
@@ -97,6 +97,11 @@ public class AgvQueueServiceImpl implements IAgvQueueService
|
|||||||
return agvQueueMapper.selectAgvQueueByTaskCode(taskCode);
|
return agvQueueMapper.selectAgvQueueByTaskCode(taskCode);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public AgvQueue selectAgvQueueByStatus() {
|
||||||
|
return agvQueueMapper.selectAgvQueueByStatus();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void insertHistory(String reqCode) {
|
public void insertHistory(String reqCode) {
|
||||||
agvQueueMapper.insertHistory(reqCode);
|
agvQueueMapper.insertHistory(reqCode);
|
||||||
|
|||||||
@@ -60,26 +60,6 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
|||||||
<include refid="selectBasCargoSpaceVo"/>
|
<include refid="selectBasCargoSpaceVo"/>
|
||||||
where cargo_space_id = #{cargoSpaceId}
|
where cargo_space_id = #{cargoSpaceId}
|
||||||
</select>
|
</select>
|
||||||
|
|
||||||
<select id="countOutboundBlockingPositions" resultType="int">
|
|
||||||
SELECT COUNT(1)
|
|
||||||
FROM bas_cargo_space outer_space
|
|
||||||
INNER JOIN bas_cargo_space requested
|
|
||||||
ON requested.cargo_space_id = #{cargoSpaceId}
|
|
||||||
AND outer_space.the_floor = requested.the_floor
|
|
||||||
AND outer_space.group_coding_no = requested.group_coding_no
|
|
||||||
AND outer_space.group_coding > requested.group_coding
|
|
||||||
WHERE NULLIF(LTRIM(RTRIM(outer_space.tray_code)), '') IS NOT NULL
|
|
||||||
OR ISNULL(NULLIF(LTRIM(RTRIM(outer_space.status)), ''), '0') <> '0'
|
|
||||||
OR ISNULL(NULLIF(LTRIM(RTRIM(outer_space.locked)), ''), '0') <> '0'
|
|
||||||
OR EXISTS (
|
|
||||||
SELECT 1
|
|
||||||
FROM mydo_job_wcs pending
|
|
||||||
WHERE pending.cargo_space_id = outer_space.cargo_space_id
|
|
||||||
AND pending.in_or_out >= 20
|
|
||||||
AND ISNULL(pending.status, '') <> '4'
|
|
||||||
)
|
|
||||||
</select>
|
|
||||||
<select id="selectBasCargoSpaceByWmsCargoSpaceId"
|
<select id="selectBasCargoSpaceByWmsCargoSpaceId"
|
||||||
resultMap="BasCargoSpaceResult">
|
resultMap="BasCargoSpaceResult">
|
||||||
<include refid="selectBasCargoSpaceVo"/>
|
<include refid="selectBasCargoSpaceVo"/>
|
||||||
|
|||||||
@@ -62,6 +62,11 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
|||||||
where task_code = #{taskCode}
|
where task_code = #{taskCode}
|
||||||
</select>
|
</select>
|
||||||
|
|
||||||
|
<select id="selectAgvQueueByStatus" resultMap="AgvQueueResult">
|
||||||
|
select top(1)* from agv_queue
|
||||||
|
where status=0
|
||||||
|
</select>
|
||||||
|
|
||||||
<insert id="insertAgvQueue" parameterType="AgvQueue">
|
<insert id="insertAgvQueue" parameterType="AgvQueue">
|
||||||
insert into agv_queue
|
insert into agv_queue
|
||||||
<trim prefix="(" suffix=")" suffixOverrides=",">
|
<trim prefix="(" suffix=")" suffixOverrides=",">
|
||||||
|
|||||||
@@ -262,10 +262,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
|||||||
a.target_cargo_space_id,
|
a.target_cargo_space_id,
|
||||||
ROW_NUMBER() OVER (
|
ROW_NUMBER() OVER (
|
||||||
PARTITION BY b.the_floor, b.group_coding_no
|
PARTITION BY b.the_floor, b.group_coding_no
|
||||||
ORDER BY b.group_coding DESC,
|
ORDER BY b.group_coding desc
|
||||||
CASE WHEN a.in_or_out = 30 THEN 0 ELSE 1 END,
|
|
||||||
a.create_time ASC,
|
|
||||||
a.job_id ASC
|
|
||||||
) AS rn
|
) AS rn
|
||||||
FROM mydo_job_wcs a
|
FROM mydo_job_wcs a
|
||||||
INNER JOIN bas_cargo_space b
|
INNER JOIN bas_cargo_space b
|
||||||
|
|||||||
@@ -1,113 +0,0 @@
|
|||||||
package com.ruoyi.api.service.impl;
|
|
||||||
|
|
||||||
import com.ruoyi.api.domain.wcs2wms.ReceiveJob;
|
|
||||||
import com.ruoyi.bas.cargospace.domain.BasCargoSpace;
|
|
||||||
import com.ruoyi.bas.cargospace.mapper.BasCargoSpaceMapper;
|
|
||||||
import com.ruoyi.common.core.domain.AjaxResult;
|
|
||||||
import com.ruoyi.job.service.IMydoJobService;
|
|
||||||
import org.junit.jupiter.api.BeforeEach;
|
|
||||||
import org.junit.jupiter.api.Test;
|
|
||||||
import org.junit.jupiter.api.extension.ExtendWith;
|
|
||||||
import org.mockito.Mock;
|
|
||||||
import org.mockito.junit.jupiter.MockitoExtension;
|
|
||||||
import org.springframework.test.util.ReflectionTestUtils;
|
|
||||||
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
|
||||||
import static org.mockito.ArgumentMatchers.any;
|
|
||||||
import static org.mockito.Mockito.never;
|
|
||||||
import static org.mockito.Mockito.verify;
|
|
||||||
import static org.mockito.Mockito.when;
|
|
||||||
|
|
||||||
@ExtendWith(MockitoExtension.class)
|
|
||||||
class ApiServiceImplTest {
|
|
||||||
@Mock
|
|
||||||
private IMydoJobService mydoJobService;
|
|
||||||
@Mock
|
|
||||||
private BasCargoSpaceMapper basCargoSpaceMapper;
|
|
||||||
|
|
||||||
private ApiServiceImpl service;
|
|
||||||
|
|
||||||
@BeforeEach
|
|
||||||
void setUp() {
|
|
||||||
service = new ApiServiceImpl();
|
|
||||||
ReflectionTestUtils.setField(service, "mydoJobService", mydoJobService);
|
|
||||||
ReflectionTestUtils.setField(service, "basCargoSpaceMapper", basCargoSpaceMapper);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void blockedOrdinaryOutboundIsNotInserted() {
|
|
||||||
ReceiveJob job = outbound("60979", "130803", "20");
|
|
||||||
when(basCargoSpaceMapper.selectBasCargoSpaceByCargoSpaceId("130803"))
|
|
||||||
.thenReturn(cargoSpace("130803"));
|
|
||||||
when(basCargoSpaceMapper.countOutboundBlockingPositions("130803")).thenReturn(1);
|
|
||||||
|
|
||||||
AjaxResult result = service.receiveOutMydoJob(job);
|
|
||||||
|
|
||||||
assertEquals(500, result.get(AjaxResult.CODE_TAG));
|
|
||||||
assertEquals("同通道外侧货位尚未清空,等待前置移库完成", result.get(AjaxResult.MSG_TAG));
|
|
||||||
verify(mydoJobService, never()).insertMydoJob(any());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void moveJobBypassesOutboundGuard() {
|
|
||||||
ReceiveJob job = outbound("80183", "120703", "30");
|
|
||||||
when(mydoJobService.insertMydoJob(any())).thenReturn(1);
|
|
||||||
|
|
||||||
AjaxResult result = service.receiveOutMydoJob(job);
|
|
||||||
|
|
||||||
assertEquals(200, result.get(AjaxResult.CODE_TAG));
|
|
||||||
verify(basCargoSpaceMapper, never()).countOutboundBlockingPositions(any());
|
|
||||||
verify(mydoJobService).insertMydoJob(any());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void unblockedOrdinaryOutboundIsInserted() {
|
|
||||||
ReceiveJob job = outbound("60979", "130803", "20");
|
|
||||||
when(basCargoSpaceMapper.selectBasCargoSpaceByCargoSpaceId("130803"))
|
|
||||||
.thenReturn(cargoSpace("130803"));
|
|
||||||
when(basCargoSpaceMapper.countOutboundBlockingPositions("130803")).thenReturn(0);
|
|
||||||
when(mydoJobService.insertMydoJob(any())).thenReturn(1);
|
|
||||||
|
|
||||||
AjaxResult result = service.receiveOutMydoJob(job);
|
|
||||||
|
|
||||||
assertEquals(200, result.get(AjaxResult.CODE_TAG));
|
|
||||||
verify(mydoJobService).insertMydoJob(any());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void unknownCargoSpaceIsRejectedInsteadOfAssumedSafe() {
|
|
||||||
ReceiveJob job = outbound("60979", "UNKNOWN", "20");
|
|
||||||
|
|
||||||
AjaxResult result = service.receiveOutMydoJob(job);
|
|
||||||
|
|
||||||
assertEquals(500, result.get(AjaxResult.CODE_TAG));
|
|
||||||
assertEquals("WCS 未找到出库货位 UNKNOWN,任务未接收", result.get(AjaxResult.MSG_TAG));
|
|
||||||
verify(mydoJobService, never()).insertMydoJob(any());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void invalidOutboundTypeIsRejectedInsteadOfBypassingGuard() {
|
|
||||||
ReceiveJob job = outbound("60979", "130803", "invalid");
|
|
||||||
|
|
||||||
AjaxResult result = service.receiveOutMydoJob(job);
|
|
||||||
|
|
||||||
assertEquals(500, result.get(AjaxResult.CODE_TAG));
|
|
||||||
assertEquals("WCS 无法识别作业类型 invalid,任务未接收", result.get(AjaxResult.MSG_TAG));
|
|
||||||
verify(mydoJobService, never()).insertMydoJob(any());
|
|
||||||
}
|
|
||||||
|
|
||||||
private ReceiveJob outbound(String jobId, String cargoSpaceId, String inOrOut) {
|
|
||||||
ReceiveJob job = new ReceiveJob();
|
|
||||||
job.setJobId(jobId);
|
|
||||||
job.setCargoSpaceId(cargoSpaceId);
|
|
||||||
job.setInOrOut(inOrOut);
|
|
||||||
job.setClassId("1");
|
|
||||||
return job;
|
|
||||||
}
|
|
||||||
|
|
||||||
private BasCargoSpace cargoSpace(String cargoSpaceId) {
|
|
||||||
BasCargoSpace cargoSpace = new BasCargoSpace();
|
|
||||||
cargoSpace.setCargoSpaceId(cargoSpaceId);
|
|
||||||
return cargoSpace;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -119,6 +119,7 @@ public class SecurityConfig
|
|||||||
.antMatchers("/api/agv/**").permitAll()
|
.antMatchers("/api/agv/**").permitAll()
|
||||||
.antMatchers("/device/api/**").permitAll()
|
.antMatchers("/device/api/**").permitAll()
|
||||||
.antMatchers("/wcs2Wms/api/**").permitAll()
|
.antMatchers("/wcs2Wms/api/**").permitAll()
|
||||||
|
.antMatchers("/agv/api/**").permitAll()
|
||||||
.antMatchers("/test/**").permitAll()
|
.antMatchers("/test/**").permitAll()
|
||||||
.antMatchers("/largeScreen/monitor/**").permitAll()
|
.antMatchers("/largeScreen/monitor/**").permitAll()
|
||||||
// 除上面外的所有请求全部需要鉴权认证
|
// 除上面外的所有请求全部需要鉴权认证
|
||||||
|
|||||||
9
ruoyi-ui/src/api/algorithm/tidy.js
Normal file
9
ruoyi-ui/src/api/algorithm/tidy.js
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
import request from '@/utils/request'
|
||||||
|
|
||||||
|
export function getTidyStatus() {
|
||||||
|
return request({ url: '/algorithm/tidy/status', method: 'get' })
|
||||||
|
}
|
||||||
|
|
||||||
|
export function updateTidyMode(mode) {
|
||||||
|
return request({ url: '/algorithm/tidy/mode', method: 'put', data: { mode } })
|
||||||
|
}
|
||||||
33
ruoyi-ui/src/views/algorithm/tidy/index.vue
Normal file
33
ruoyi-ui/src/views/algorithm/tidy/index.vue
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
<template>
|
||||||
|
<div class="app-container tidy-page">
|
||||||
|
<el-card>
|
||||||
|
<div slot="header"><span>理货控制</span></div>
|
||||||
|
<el-switch v-model="manual" active-text="手动理货" inactive-text="自动理货" :disabled="loading || !hasEdit" @change="changeMode" />
|
||||||
|
<span class="mode-status">当前模式:{{ modeLabel }}</span>
|
||||||
|
</el-card>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import { getTidyStatus, updateTidyMode } from '@/api/algorithm/tidy'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'TidyControl',
|
||||||
|
data() { return { manual: false, mode: 'AUTO', loading: false, timer: null, hasEdit: this.$auth.hasPermi('algorithm:tidy:edit') } },
|
||||||
|
computed: { modeLabel() { return this.mode === 'MANUAL' ? '手动' : '自动' } },
|
||||||
|
created() { this.refresh(); this.timer = setInterval(this.refresh, 5000) },
|
||||||
|
beforeDestroy() { if (this.timer) { clearInterval(this.timer); this.timer = null } },
|
||||||
|
methods: {
|
||||||
|
refresh() { getTidyStatus().then(res => { const data = res.data || {}; this.mode = data.mode || 'AUTO'; this.manual = this.mode === 'MANUAL' }).catch(() => {}) },
|
||||||
|
changeMode(value) {
|
||||||
|
const previous = this.mode
|
||||||
|
this.loading = true
|
||||||
|
updateTidyMode(value ? 'MANUAL' : 'AUTO').then(res => { const data = res.data || {}; this.mode = data.mode || (value ? 'MANUAL' : 'AUTO') }).catch(() => { this.manual = previous === 'MANUAL'; this.$message.error('理货模式切换失败') }).finally(() => { this.loading = false })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.mode-status { margin-left: 16px; color: #606266; }
|
||||||
|
</style>
|
||||||
@@ -157,7 +157,6 @@ export default {
|
|||||||
{ key: 'kx', label: '空闲', value: d.kx, dict: 'ssj_kx' },
|
{ key: 'kx', label: '空闲', value: d.kx, dict: 'ssj_kx' },
|
||||||
{ key: 'dw', label: '到位', value: d.dw, dict: 'ssj_dw' },
|
{ key: 'dw', label: '到位', value: d.dw, dict: 'ssj_dw' },
|
||||||
{ key: 'exception', label: '异常', value: d.exception, dict: 'ssj_ex'},
|
{ key: 'exception', label: '异常', value: d.exception, dict: 'ssj_ex'},
|
||||||
|
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
if (dev.kind === 'srgv') {
|
if (dev.kind === 'srgv') {
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ const CompressionPlugin = require('compression-webpack-plugin')
|
|||||||
|
|
||||||
const name = process.env.VUE_APP_TITLE || 'FORTUCKY WCS SYSTEM' // 网页标题
|
const name = process.env.VUE_APP_TITLE || 'FORTUCKY WCS SYSTEM' // 网页标题
|
||||||
|
|
||||||
const baseUrl = 'http://localhost:8081' // 后端接口地址(你的后端端口是8081)
|
const baseUrl = 'http://192.168.188.236:8081' // 后端接口地址(你的后端端口是8081)
|
||||||
|
|
||||||
const port = process.env.port || process.env.npm_config_port || 80 // 前端端口
|
const port = process.env.port || process.env.npm_config_port || 80 // 前端端口
|
||||||
|
|
||||||
@@ -18,6 +18,7 @@ module.exports = {
|
|||||||
outputDir: 'dist',
|
outputDir: 'dist',
|
||||||
assetsDir: 'static',
|
assetsDir: 'static',
|
||||||
productionSourceMap: false,
|
productionSourceMap: false,
|
||||||
|
parallel: false,
|
||||||
transpileDependencies: ['quill'],
|
transpileDependencies: ['quill'],
|
||||||
devServer: {
|
devServer: {
|
||||||
host: '0.0.0.0',
|
host: '0.0.0.0',
|
||||||
|
|||||||
Reference in New Issue
Block a user