1. 小幅更新托盘库的入库流程,与上层商量后改为先调用query接口查询是否可上料,可上料才能调用orderIn接口,之后轮询agvDone接口,直到返回0,即入库订单状态更新完成,将入库任务推送wcs入库

2. 删除托盘库和料箱库的资源锁插件
This commit is contained in:
李宇奇 2025-09-23 21:59:47 +08:00
parent c81c639a19
commit 0e5b01739c
22 changed files with 266 additions and 1161 deletions

View File

@ -1,14 +1,14 @@
### MyWMS接口测试 ### MyWMS接口测试
### 基础配置 ### 基础配置
@baseUrl = http://localhost:12315 @baseUrl = http://localhost:12325
### 1. 入库订单接口 ### 1. 入库订单接口
POST {{baseUrl}}/mywms/orderIn POST {{baseUrl}}/mywms/orderIn
Content-Type: application/json Content-Type: application/json
{ {
"taskId": "testOrderId9", "taskId": "testId1",
"vehicleNo": "1002" "vehicleNo": "1001"
} }
### 2. 出库订单接口 ### 2. 出库订单接口
@ -16,54 +16,18 @@ POST {{baseUrl}}/mywms/orderOut
Content-Type: application/json Content-Type: application/json
{ {
"taskId": "testOrderId1", "taskId": "testId1",
"vehicleNo": "1002" "vehicleNo": "1002"
} }
### 3. 库存查询接口 - 仅按载具查询 ### 3. 发送任务结果 - 任务完成
POST {{baseUrl}}/mywms/stock POST {{baseUrl}}/wms/task/sendTaskResult
Content-Type: application/json Content-Type: application/json
{ {
"requestId": "testOrderId1", "taskId": "1758635063394010001",
"details": [ "taskStatus": 100,
{ "vehicleNo": "1009",
"vehicleNo": "1002" "destination": "CR",
} "message": "任务执行成功"
] }
}
### 4. 库存查询接口 - 仅按库位查询
POST {{baseUrl}}/mywms/stock
Content-Type: application/json
{
"requestId": "testOrderId2",
"details": [
{
"locationId": "A02-01-02-02"
}
]
}
### 5. 检查是否允许投料
GET {{baseUrl}}/mywms/allowFeed
### 6. 允许出库
GET {{baseUrl}}/mywms/allowOut
### 测试数据说明
# 1. orderIn: 入库订单接口需要taskId和vehicleNo
# 2. orderOut: 出库订单接口需要taskId和vehicleNo
# 3. stock: 库存查询接口需要requestId和details数组
# - details中可以包含vehicleNo和/或locationId
# 4. allowFeed: 查询当前系统是否允许投料操作GET请求
### 响应格式说明
# 所有接口都返回MyWmsResponse格式:
# {
# "code": 200, // 响应码
# "message": "操作成功", // 响应消息
# "data": {}, // 具体数据
# "success": true // 是否成功
# }

View File

@ -1,60 +0,0 @@
### TaskController接口测试 - WMS任务控制接口
### 基础配置
@baseUrl = http://localhost:12315
### 1. WCS请求载具入库
POST {{baseUrl}}/wms/task/wcsRequestVehicleIn
Content-Type: application/json
{
"origin": "CR",
"vehicleNo": "1002",
"codeMessage": "test",
"remark": "载具入库测试"
}
### 2. 发送任务结果 - 任务完成
POST {{baseUrl}}/wms/task/sendTaskResult
Content-Type: application/json
{
"taskId": "1756881794848010000",
"taskStatus": 100,
"vehicleNo": "1009",
"destination": "CR",
"message": "任务执行成功"
}
### 测试数据说明
# 1. wcsRequestVehicleIn: WCS请求载具入库
# - origin: 点位(必填)
# - vehicleNo: 载具信息(必填)
# - codeMessage: 条码信息(可选)
# - remark: 备注(可选)
# 2. sendTaskResult: WCS反馈任务执行结果
# - taskId: 任务ID必填
# - taskStatus: 任务状态(必填)
# * 0: 等待执行
# * 1: 执行中
# * 2: 执行完成
# * 3: 执行失败
# - vehicleNo: 载具号(必填)
# - destination: 终点(可选)
# - message: 信息(可选)
### 响应格式说明
# wcsRequestVehicleIn返回WcsVehicleInResponse:
# {
# "success": true,
# "code": "SUCCESS",
# "message": "请求成功",
# "data": {}
# }
# sendTaskResult返回BaseWcsApiResponse:
# {
# "success": true,
# "code": "SUCCESS",
# "message": "任务结果接收成功"
# }

View File

@ -90,6 +90,7 @@ public class HttpClient {
/** /**
* 发送一个 Post 请求 * 发送一个 Post 请求
*
* @param request 请求数据 * @param request 请求数据
* @return 响应数据 * @return 响应数据
*/ */
@ -97,14 +98,14 @@ public class HttpClient {
log.info("请求信息{}", StringUtils.objectToString(request)); log.info("请求信息{}", StringUtils.objectToString(request));
HttpResponse response = new HttpResponse(); HttpResponse response = new HttpResponse();
String url = request.getUrl(); String url = request.getUrl();
if(StringUtils.isEmpty(url)) { if (StringUtils.isEmpty(url)) {
// 请求地址没传 // 请求地址没传
response.setSuccess(false); response.setSuccess(false);
response.setResponseCode(999); response.setResponseCode(999);
response.setException(new Exception("请求地址为空")); response.setException(new Exception("请求地址为空"));
return response; return response;
} }
if(StringUtils.isEmpty(request.getData())) { if (StringUtils.isEmpty(request.getData())) {
request.setData("{}"); request.setData("{}");
} }
response.setRequestUrl(url); response.setRequestUrl(url);
@ -113,11 +114,12 @@ public class HttpClient {
CloseableHttpClient httpClient = HttpClientBuilder.create().build(); CloseableHttpClient httpClient = HttpClientBuilder.create().build();
HttpPost postRequest = new HttpPost(url); HttpPost postRequest = new HttpPost(url);
postRequest.setHeader("Content-Type", request.getContentType()); postRequest.setHeader("Content-Type", request.getContentType());
postRequest.setHeader("Authorization", request.getToken()); postRequest.setHeader("Expect", "100-continue");
// postRequest.setHeader("Authorization", request.getToken());
// 设置请求头 // 设置请求头
for(Map.Entry<String, String> entry : request.getHeader().entrySet()){ // for(Map.Entry<String, String> entry : request.getHeader().entrySet()){
postRequest.setHeader(entry.getKey(), entry.getValue()); // postRequest.setHeader(entry.getKey(), entry.getValue());
} // }
postRequest.setEntity(new StringEntity(request.getData())); postRequest.setEntity(new StringEntity(request.getData()));
RequestConfig requestConfig = RequestConfig.custom() RequestConfig requestConfig = RequestConfig.custom()
.setConnectTimeout(request.getTimeout()) .setConnectTimeout(request.getTimeout())

View File

@ -46,7 +46,6 @@ public class WcsApiServiceImpl implements IWcsApiService {
// response = httpResponse.getData(response.getClass().asSubclass(WcsApiResponse.class)); // response = httpResponse.getData(response.getClass().asSubclass(WcsApiResponse.class));
// return response; // return response;
// } // }
// TODO success -> error
return WcsApiResponse.success("请求未获得响应信息。", null); return WcsApiResponse.success("请求未获得响应信息。", null);
} }
@ -116,7 +115,6 @@ public class WcsApiServiceImpl implements IWcsApiService {
// response = httpResponse.getData(response.getClass().asSubclass(WcsApiResponse.class)); // response = httpResponse.getData(response.getClass().asSubclass(WcsApiResponse.class));
// return response; // return response;
// } // }
// TODO error -> success
// return WcsApiResponse.error("请求未获得响应信息。", null); // return WcsApiResponse.error("请求未获得响应信息。", null);
WcsCanFeedResponse wcsCanFeedResponse = new WcsCanFeedResponse(); WcsCanFeedResponse wcsCanFeedResponse = new WcsCanFeedResponse();
wcsCanFeedResponse.setResponseTime(LocalDateTime.now()); wcsCanFeedResponse.setResponseTime(LocalDateTime.now());

View File

@ -1,52 +0,0 @@
package com.wms_main.service.business;
import com.wms_main.model.po.TAppAgvLock;
/**
* 入库口互锁服务接口
* 管理单一入库口的AGV上料互锁机制
*/
public interface IAgvLockService {
/**
* AGV就位并放货后锁定入库口
* @param agvId AGV设备ID
* @param inboundPort 入库口编号
* @return 锁定结果成功返回锁定记录失败返回null
*/
TAppAgvLock lockInboundPort(String agvId, String inboundPort);
/**
* 检查入库口是否可以上料MES系统调用
* @param inboundPort 入库口编号
* @return 是否可以上料
*/
boolean canFeedToInboundPort(String inboundPort);
/**
* 获取当前入库口处理中的任务数量
* @param inboundPort 入库口编号
* @return 处理中的任务数量
*/
int getProcessingTaskCount(String inboundPort);
/**
* 获取入库口状态描述
* @param inboundPort 入库口编号
* @return 状态描述空闲/占用
*/
String getInboundPortStatus(String inboundPort);
/**
* 清理超时锁定
* @return 清理的记录数
*/
int cleanTimeoutLocks();
/**
* 释放指定入库口的所有活动锁定
* @param inboundPort 入库口编号
* @return 释放的锁定数量
*/
int releaseAllInboundPortLocks(String inboundPort);
}

View File

@ -1,232 +0,0 @@
package com.wms_main.service.business.serviceImpl;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.wms_main.constant.enums.wms.WmsAgvLockEnums;
import com.wms_main.dao.ITAppAgvLockService;
import com.wms_main.dao.ITAppTaskService;
import com.wms_main.model.po.TAppAgvLock;
import com.wms_main.model.po.TAppTask;
import com.wms_main.constant.enums.wms.WmsTaskTypeEnums;
import com.wms_main.constant.enums.wms.WmsStackerTaskStatusEnums;
import com.wms_main.repository.utils.StringUtils;
import com.wms_main.repository.utils.UUIDUtils;
import com.wms_main.service.business.IAgvLockService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.time.LocalDateTime;
import java.util.List;
/**
* 入库口互锁服务实现
* 管理单一入库口的AGV上料互锁机制
*/
@Service
@RequiredArgsConstructor
@Slf4j
public class AgvLockServiceImpl implements IAgvLockService {
private final ITAppAgvLockService agvLockService;
private final ITAppTaskService appTaskService;
private static final String DEFAULT_INBOUND_PORT = "R1"; // 默认入库口
private static final int DEFAULT_TIMEOUT_SECONDS = 600; // 默认超时时间10分钟
@Override
@Transactional
public TAppAgvLock lockInboundPort(String agvId, String inboundPort) {
if (StringUtils.isEmpty(agvId)) {
log.warn("AGV ID为空");
return null;
}
// 使用默认入库口如果未指定
if (StringUtils.isEmpty(inboundPort)) {
inboundPort = DEFAULT_INBOUND_PORT;
}
// 清理超时锁定
cleanTimeoutLocks();
// 检查入库口是否已被占用
List<TAppAgvLock> existingLocks = agvLockService.list(new LambdaQueryWrapper<TAppAgvLock>().eq(TAppAgvLock::getFeedStation, inboundPort));
if (existingLocks == null || existingLocks.isEmpty()) {
return createInboundPortLock(agvId, inboundPort);
} else {
agvLockService.update(
new LambdaUpdateWrapper<TAppAgvLock>()
.eq(TAppAgvLock::getFeedStation, inboundPort)
.eq(TAppAgvLock::getLockStatus, WmsAgvLockEnums.AVAILABLE.getCode())
.set(TAppAgvLock::getLockStatus, WmsAgvLockEnums.LOCK.getCode())
.set(TAppAgvLock::getLockTime, LocalDateTime.now())
.set(TAppAgvLock::getRemark, "AGV就位并放货锁定入库口")
);
return null;
}
}
@Override
public boolean canFeedToInboundPort(String inboundPort) {
// 使用默认入库口如果未指定
if (StringUtils.isEmpty(inboundPort)) {
inboundPort = DEFAULT_INBOUND_PORT;
}
// 清理超时锁定
cleanTimeoutLocks();
// 检查入库口是否有活动的锁定
List<TAppAgvLock> activeLocks = agvLockService.getByStation(inboundPort);
boolean hasActiveLock = activeLocks.stream()
.anyMatch(lock -> lock.getLockStatus() == 1);
if (hasActiveLock) {
log.debug("入库口 {} 当前被占用,无法上料", inboundPort);
return false;
}
// 检查是否有正在处理的入库任务
int processingTasks = getProcessingTaskCount(inboundPort);
boolean canFeed = processingTasks == 0;
log.debug("入库口 {} 可上料状态: {}, 处理中任务数: {}", inboundPort, canFeed, processingTasks);
return canFeed;
}
@Override
public int getProcessingTaskCount(String inboundPort) {
// 使用默认入库口如果未指定
if (StringUtils.isEmpty(inboundPort)) {
inboundPort = DEFAULT_INBOUND_PORT;
}
// 统计正在处理的入库任务数量包括等待运行状态的任务
List<TAppTask> processingTasks = appTaskService.list(
new LambdaQueryWrapper<TAppTask>()
.eq(TAppTask::getTaskType, WmsTaskTypeEnums.IN.getCode())
.in(TAppTask::getTaskStatus,
WmsStackerTaskStatusEnums.WAIT.getCode(),
WmsStackerTaskStatusEnums.RUN.getCode())
.like(TAppTask::getOrigin, inboundPort) // 假设任务来源包含入库口信息
);
return processingTasks.size();
}
@Override
public String getInboundPortStatus(String inboundPort) {
// 使用默认入库口如果未指定
if (StringUtils.isEmpty(inboundPort)) {
inboundPort = DEFAULT_INBOUND_PORT;
}
// 检查是否有活动锁定
List<TAppAgvLock> activeLocks = agvLockService.getByStation(inboundPort);
boolean hasActiveLock = activeLocks.stream()
.anyMatch(lock -> lock.getLockStatus() == 1);
if (hasActiveLock) {
return "占用";
}
// 检查是否有处理中的任务
int processingTasks = getProcessingTaskCount(inboundPort);
if (processingTasks > 0) {
return "占用";
}
return "空闲";
}
@Override
@Transactional
public int cleanTimeoutLocks() {
List<TAppAgvLock> timeoutLocks = agvLockService.getTimeoutLocks();
if (timeoutLocks.isEmpty()) {
return 0;
}
try {
for (TAppAgvLock lock : timeoutLocks) {
agvLockService.update(
new LambdaUpdateWrapper<TAppAgvLock>()
.eq(TAppAgvLock::getLockId, lock.getLockId())
.set(TAppAgvLock::getLockStatus, 0)
.set(TAppAgvLock::getUnlockTime, LocalDateTime.now())
.set(TAppAgvLock::getRemark, "超时自动释放")
);
log.info("释放超时锁定: AGV {} 在入库口 {}", lock.getAgvId(), lock.getFeedStation());
}
log.info("清理了 {} 个超时锁定", timeoutLocks.size());
return timeoutLocks.size();
} catch (Exception e) {
log.error("清理超时锁定失败", e);
return 0;
}
}
@Override
@Transactional
public int releaseAllInboundPortLocks(String inboundPort) {
// 使用默认入库口如果未指定
if (StringUtils.isEmpty(inboundPort)) {
inboundPort = DEFAULT_INBOUND_PORT;
}
try {
// 释放指定入库口的所有活动锁定
agvLockService.update(
new LambdaUpdateWrapper<TAppAgvLock>()
.eq(TAppAgvLock::getFeedStation, inboundPort)
.eq(TAppAgvLock::getLockStatus, WmsAgvLockEnums.LOCK.getCode())
.set(TAppAgvLock::getLockStatus, WmsAgvLockEnums.AVAILABLE.getCode())
.set(TAppAgvLock::getUnlockTime, LocalDateTime.now())
.set(TAppAgvLock::getRemark, "入库任务完成,批量释放锁定")
);
// 查询实际释放的锁定数量
List<TAppAgvLock> activeLocks = agvLockService.getByStation(inboundPort);
int releasedCount = (int) activeLocks.stream()
.filter(lock -> lock.getLockStatus() == 0)
.count();
log.info("释放入库口 {} 的所有锁定,共释放 {} 个锁定", inboundPort, releasedCount);
return releasedCount;
} catch (Exception e) {
log.error("释放入库口 {} 的所有锁定失败", inboundPort, e);
return 0;
}
}
/**
* 创建入库口锁定记录
*/
private TAppAgvLock createInboundPortLock(String agvId, String inboundPort) {
TAppAgvLock lock = new TAppAgvLock();
lock.setLockId(UUIDUtils.getNewUUID());
lock.setAgvId(agvId);
lock.setFeedStation(inboundPort);
lock.setLockStatus(1);
lock.setLockType("INBOUND_PORT_LOCK");
lock.setPriority(1);
lock.setQueuePosition(1);
lock.setLockTime(LocalDateTime.now());
lock.setTimeoutSeconds(DEFAULT_TIMEOUT_SECONDS);
lock.setCreateTime(LocalDateTime.now());
lock.setUpdateTime(LocalDateTime.now());
lock.setRemark("AGV就位并放货锁定入库口");
if (agvLockService.save(lock)) {
log.info("AGV {} 成功锁定入库口 {}", agvId, inboundPort);
return lock;
}
log.error("AGV {} 锁定入库口 {} 失败", agvId, inboundPort);
return null;
}
}

View File

@ -9,12 +9,12 @@ import com.wms_main.constant.enums.wms.*;
import com.wms_main.dao.*; import com.wms_main.dao.*;
import com.wms_main.model.dto.request.mywms.OrderInCBReq; import com.wms_main.model.dto.request.mywms.OrderInCBReq;
import com.wms_main.model.dto.request.mywms.OrderOutCBReq; import com.wms_main.model.dto.request.mywms.OrderOutCBReq;
import com.wms_main.model.dto.response.mes.MesApiResponse;
import com.wms_main.model.po.*; import com.wms_main.model.po.*;
import com.wms_main.repository.utils.ConvertUtils; import com.wms_main.repository.utils.ConvertUtils;
import com.wms_main.repository.utils.StringUtils; import com.wms_main.repository.utils.StringUtils;
import com.wms_main.repository.utils.UUIDUtils; import com.wms_main.repository.utils.UUIDUtils;
import com.wms_main.service.api.IExternalApiService; import com.wms_main.service.api.IExternalApiService;
import com.wms_main.service.business.IAgvLockService;
import com.wms_main.service.business.IStackerTaskService; import com.wms_main.service.business.IStackerTaskService;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
@ -25,7 +25,6 @@ import java.time.LocalDateTime;
import java.util.*; import java.util.*;
import java.util.stream.Collectors; import java.util.stream.Collectors;
/** /**
* 服务实现 * 服务实现
*/ */
@ -73,8 +72,6 @@ public class StackerTaskServiceImpl implements IStackerTaskService {
*/ */
private final AppCommon appCommon; private final AppCommon appCommon;
private final IAgvLockService agvLockService;
/** /**
* 存WcsTask表 * 存WcsTask表
* 更新WmsTask表 * 更新WmsTask表
@ -92,9 +89,9 @@ public class StackerTaskServiceImpl implements IStackerTaskService {
.set(TAppTask::getWcsTaskId, wcsTask.getWcsTaskId()) .set(TAppTask::getWcsTaskId, wcsTask.getWcsTaskId())
.set(TAppTask::getTaskStatus, WmsStackerTaskStatusEnums.EXECUTED.getCode()) .set(TAppTask::getTaskStatus, WmsStackerTaskStatusEnums.EXECUTED.getCode())
.eq(TAppTask::getVehicleId, wcsTask.getVehicleId()) .eq(TAppTask::getVehicleId, wcsTask.getVehicleId())
.eq(TAppTask::getTaskType, ConvertUtils.convertStackerTaskTypeFromWcsToWms(wcsTask.getWcsTaskType())) .eq(TAppTask::getTaskType,
.eq(TAppTask::getTaskStatus, WmsStackerTaskStatusEnums.WAIT.getCode()) ConvertUtils.convertStackerTaskTypeFromWcsToWms(wcsTask.getWcsTaskType()))
); .eq(TAppTask::getTaskStatus, WmsStackerTaskStatusEnums.WAIT.getCode()));
} }
/** /**
@ -131,33 +128,36 @@ public class StackerTaskServiceImpl implements IStackerTaskService {
// 查询库位 // 查询库位
List<TAppLocation> locationList = appLocationService.list(queryWrapper); List<TAppLocation> locationList = appLocationService.list(queryWrapper);
List<TAppLocation> candidateLocationList = locationList.stream().filter(item -> { List<TAppLocation> candidateLocationList = locationList.stream().filter(item -> {
boolean filterResult = item.getIsWorking() == 0 && item.getIsLock() == 0 && item.getIsOccupy() == 0; boolean filterResult = item.getIsWorking() == 0 && item.getIsLock() == 0 && item.getIsOccupy() == 0;
if (locationFilter != null) { if (locationFilter != null) {
if (locationFilter.getLRow() != null) { if (locationFilter.getLRow() != null) {
filterResult = filterResult && Objects.equals(item.getLRow(), locationFilter.getLRow()); filterResult = filterResult && Objects.equals(item.getLRow(), locationFilter.getLRow());
} }
if (locationFilter.getLCol() != null) { if (locationFilter.getLCol() != null) {
filterResult = filterResult && Objects.equals(item.getLCol(), locationFilter.getLCol()); filterResult = filterResult && Objects.equals(item.getLCol(), locationFilter.getLCol());
} }
if (locationFilter.getLLayer() != null) { if (locationFilter.getLLayer() != null) {
filterResult = filterResult && Objects.equals(item.getLLayer(), locationFilter.getLLayer()); filterResult = filterResult && Objects.equals(item.getLLayer(), locationFilter.getLLayer());
} }
} }
return filterResult; return filterResult;
}).sorted(Comparator.comparingInt(TAppLocation::getLDepth).reversed()) }).sorted(Comparator.comparingInt(TAppLocation::getLDepth).reversed())
.sorted(Comparator.comparingInt(location -> location.getLCol() + location.getLLayer())) .sorted(Comparator.comparingInt(location -> location.getLCol() + location.getLLayer()))
.toList(); .toList();
// 判断是否输入了subArea // 判断是否输入了subArea
if (locationFilter != null && StringUtils.isNotEmpty(locationFilter.getSubArea())) { if (locationFilter != null && StringUtils.isNotEmpty(locationFilter.getSubArea())) {
// 对candidateLocationList进行排序 // 对candidateLocationList进行排序
List<TAppLocation> firstList = candidateLocationList.stream().filter(item -> item.getSubArea().equals(locationFilter.getSubArea())).toList(); List<TAppLocation> firstList = candidateLocationList.stream()
List<TAppLocation> lastList = candidateLocationList.stream().filter(item -> !item.getSubArea().equals(locationFilter.getSubArea())).toList(); .filter(item -> item.getSubArea().equals(locationFilter.getSubArea())).toList();
List<TAppLocation> lastList = candidateLocationList.stream()
.filter(item -> !item.getSubArea().equals(locationFilter.getSubArea())).toList();
candidateLocationList = new ArrayList<>(firstList);// 先添加符合subArea的库位 candidateLocationList = new ArrayList<>(firstList);// 先添加符合subArea的库位
candidateLocationList.addAll(lastList);// 再添加不符合subArea的库位 candidateLocationList.addAll(lastList);// 再添加不符合subArea的库位
} }
// 找一个空闲的库位 // 找一个空闲的库位
for (TAppLocation candidateLocation : candidateLocationList) { for (TAppLocation candidateLocation : candidateLocationList) {
if (candidateLocation.getIsWorking() == 1 || candidateLocation.getIsLock() == 1 || candidateLocation.getIsOccupy() == 1) { if (candidateLocation.getIsWorking() == 1 || candidateLocation.getIsLock() == 1
|| candidateLocation.getIsOccupy() == 1) {
continue; continue;
} }
if (isMaxDepthAvailable(locationList, candidateLocation)) { if (isMaxDepthAvailable(locationList, candidateLocation)) {
@ -167,8 +167,7 @@ public class StackerTaskServiceImpl implements IStackerTaskService {
.set(TAppLocation::getIsOccupy, 1) .set(TAppLocation::getIsOccupy, 1)
.set(TAppLocation::getVehicleId, requestVehicleId) .set(TAppLocation::getVehicleId, requestVehicleId)
.eq(TAppLocation::getLocationId, candidateLocation.getLocationId()) .eq(TAppLocation::getLocationId, candidateLocation.getLocationId())
.eq(TAppLocation::getIsOccupy, 0) .eq(TAppLocation::getIsOccupy, 0))) {
)) {
// 当前库位可用 // 当前库位可用
targetLocation = candidateLocation; targetLocation = candidateLocation;
break; break;
@ -193,31 +192,37 @@ public class StackerTaskServiceImpl implements IStackerTaskService {
/** /**
* 获取一个堆垛机库的空库位 * 获取一个堆垛机库的空库位
*
* @param equipmentId 设备号 * @param equipmentId 设备号
* @return 返回的库位信息 * @return 返回的库位信息
*/ */
@Override @Override
public TAppLocation getEmptyLocation(Integer equipmentId, WmsLocationTypeEnums type) { public TAppLocation getEmptyLocation(Integer equipmentId, WmsLocationTypeEnums type) {
if(equipmentId == null) return null; if (equipmentId == null)
return null;
List<TAppLocation> allLocations = appLocationService.getAllLocation(equipmentId); List<TAppLocation> allLocations = appLocationService.getAllLocation(equipmentId);
if(allLocations == null || allLocations.isEmpty()) return null; if (allLocations == null || allLocations.isEmpty())
return null;
for (TAppLocation location : allLocations) { for (TAppLocation location : allLocations) {
if(location.getIsOccupy() != 0 || location.getIsLock() != 0 || location.getIsWorking() != 0){ if (location.getIsOccupy() != 0 || location.getIsLock() != 0 || location.getIsWorking() != 0) {
continue; // 不可用货位 continue; // 不可用货位
} }
if(type != null && !type.getCode().equals(location.getLocationType())) { if (type != null && !type.getCode().equals(location.getLocationType())) {
continue; continue;
} }
// 检查内侧深度是否可用 // 检查内侧深度是否可用
Integer lDepth = location.getLDepth(); Integer lDepth = location.getLDepth();
if(lDepth != null && lDepth.compareTo(1) > 0) { if (lDepth != null && lDepth.compareTo(1) > 0) {
boolean canUse = true; boolean canUse = true;
for(int i = lDepth - 1; i > 0; i--) { for (int i = lDepth - 1; i > 0; i--) {
int checkDepth = i; int checkDepth = i;
List<TAppLocation> sameColLocations = allLocations.stream().filter(item -> List<TAppLocation> sameColLocations = allLocations.stream()
item.getLRow().equals(location.getLRow()) && item.getLCol().equals(location.getLCol()) .filter(item -> item.getLRow().equals(location.getLRow())
&& item.getLLayer().equals(location.getLLayer()) && item.getLDepth().equals(checkDepth)).toList(); && item.getLCol().equals(location.getLCol())
if(sameColLocations.isEmpty()) { && item.getLLayer().equals(location.getLLayer())
&& item.getLDepth().equals(checkDepth))
.toList();
if (sameColLocations.isEmpty()) {
continue; // 库位不存在可能 continue; // 库位不存在可能
} }
TAppLocation sameColLocationsFirst = sameColLocations.getFirst(); TAppLocation sameColLocationsFirst = sameColLocations.getFirst();
@ -225,26 +230,26 @@ public class StackerTaskServiceImpl implements IStackerTaskService {
TAppStock checkIsHaveStock = new TAppStock(); TAppStock checkIsHaveStock = new TAppStock();
checkIsHaveStock.setLocationId(sameColLocationsFirst.getLocationId()); checkIsHaveStock.setLocationId(sameColLocationsFirst.getLocationId());
List<TAppStock> checkStockIsHaveStockResult = appStockService.getWithEntity(checkIsHaveStock); List<TAppStock> checkStockIsHaveStockResult = appStockService.getWithEntity(checkIsHaveStock);
if(checkStockIsHaveStockResult == null) { if (checkStockIsHaveStockResult == null) {
canUse = false; // 数据库查询失败库位直接不可用 canUse = false; // 数据库查询失败库位直接不可用
break; break;
} }
if(!checkStockIsHaveStockResult.isEmpty()) { if (!checkStockIsHaveStockResult.isEmpty()) {
canUse = false; // 库位有库存不可用 canUse = false; // 库位有库存不可用
break; break;
} }
// 校验是否存在出入库任务 // 校验是否存在出入库任务
Boolean existsTaskWithLocation = appWcsTaskService.existsTaskWithLocation(location.getLocationId()); Boolean existsTaskWithLocation = appWcsTaskService.existsTaskWithLocation(location.getLocationId());
if(existsTaskWithLocation == null) { if (existsTaskWithLocation == null) {
canUse = false; canUse = false;
break; break;
} }
if(existsTaskWithLocation) { if (existsTaskWithLocation) {
canUse = false; // 库位有任务不可用 canUse = false; // 库位有任务不可用
break; break;
} }
} }
if(!canUse) { if (!canUse) {
continue; // 不可用 continue; // 不可用
} }
return location; return location;
@ -273,11 +278,12 @@ public class StackerTaskServiceImpl implements IStackerTaskService {
return false; return false;
} }
// 查询到排列层对应的库位列表 // 查询到排列层对应的库位列表
List<TAppLocation> diffDepthLocationList = appLocationList.stream().filter(item -> List<TAppLocation> diffDepthLocationList = appLocationList.stream()
Objects.equals(item.getLRow(), appLocation.getLRow()) && .filter(item -> Objects.equals(item.getLRow(), appLocation.getLRow()) &&
Objects.equals(item.getLCol(), appLocation.getLCol()) && Objects.equals(item.getLCol(), appLocation.getLCol()) &&
Objects.equals(item.getLLayer(), appLocation.getLLayer()) && Objects.equals(item.getLLayer(), appLocation.getLLayer()) &&
!Objects.equals(item.getLDepth(), appLocation.getLDepth())).toList(); !Objects.equals(item.getLDepth(), appLocation.getLDepth()))
.toList();
// 结果 // 结果
boolean result = true; boolean result = true;
for (TAppLocation diffDepthLocation : diffDepthLocationList) { for (TAppLocation diffDepthLocation : diffDepthLocationList) {
@ -324,20 +330,24 @@ public class StackerTaskServiceImpl implements IStackerTaskService {
// 查找到所有的入库任务列表---非暂存和完成状态 // 查找到所有的入库任务列表---非暂存和完成状态
List<TAppTask> inTasks = appTaskService.list(new LambdaQueryWrapper<TAppTask>() List<TAppTask> inTasks = appTaskService.list(new LambdaQueryWrapper<TAppTask>()
.eq(TAppTask::getTaskType, WmsTaskTypeEnums.IN.getCode()) .eq(TAppTask::getTaskType, WmsTaskTypeEnums.IN.getCode())
.notIn(TAppTask::getTaskStatus, WmsStackerTaskStatusEnums.FINISH.getCode(), WmsStackerTaskStatusEnums.TEMP.getCode())); .notIn(TAppTask::getTaskStatus, WmsStackerTaskStatusEnums.FINISH.getCode(),
WmsStackerTaskStatusEnums.TEMP.getCode()));
if (inTasks == null || inTasks.isEmpty()) { if (inTasks == null || inTasks.isEmpty()) {
for (TAppLocation appLocation : emptyLocationList) { for (TAppLocation appLocation : emptyLocationList) {
if (equipCountMap.containsKey(appLocation.getEquipmentId())) { if (equipCountMap.containsKey(appLocation.getEquipmentId())) {
equipCountMap.replace(appLocation.getEquipmentId(), equipCountMap.get(appLocation.getEquipmentId()) + 1); equipCountMap.replace(appLocation.getEquipmentId(),
equipCountMap.get(appLocation.getEquipmentId()) + 1);
} }
} }
} else { } else {
for (TAppTask inTask : inTasks) { for (TAppTask inTask : inTasks) {
if (StringUtils.isNotEmpty(inTask.getDestination())) { if (StringUtils.isNotEmpty(inTask.getDestination())) {
// 当前目标库位的设备号 // 当前目标库位的设备号
TAppLocation destinationEquipmentId = appCommon.getInstantLocationByLocationId(inTask.getDestination()); TAppLocation destinationEquipmentId = appCommon
.getInstantLocationByLocationId(inTask.getDestination());
if (equipCountMap.containsKey(destinationEquipmentId.getEquipmentId())) { if (equipCountMap.containsKey(destinationEquipmentId.getEquipmentId())) {
equipCountMap.replace(destinationEquipmentId.getEquipmentId(), equipCountMap.get(destinationEquipmentId.getEquipmentId()) + 1); equipCountMap.replace(destinationEquipmentId.getEquipmentId(),
equipCountMap.get(destinationEquipmentId.getEquipmentId()) + 1);
} }
} }
} }
@ -352,7 +362,6 @@ public class StackerTaskServiceImpl implements IStackerTaskService {
.toList(); .toList();
} }
/** /**
* 实现 * 实现
* *
@ -393,25 +402,6 @@ public class StackerTaskServiceImpl implements IStackerTaskService {
.eq(TAppStock::getVehicleId, orderIn.getVehicleNo())); .eq(TAppStock::getVehicleId, orderIn.getVehicleNo()));
} }
OrderInCBReq orderInCBReq = new OrderInCBReq();
orderInCBReq.setTaskId(orderIn.getOrderId());
orderInCBReq.setVehicleNo(wmsTask.getVehicleId());
orderInCBReq.setLocationId(wmsTask.getDestination());
orderInCBReq.setResult(OrderInCBEnums.COMPLETE.getCode());
orderInCBReq.setResultMessage("入库完成");
// int times = 0;
// MesApiResponse response = null;
// do {
// Thread.sleep(15000L * times);
// response = externalApiService.invokeOrderInCB(orderInCBReq);
// times++;
// } while (response.getCode() != 0 && times <= 10);
// if (response.getCode() != 0) {
// log.error("[wms]上报失败");
// } else {
// log.info("[wms]上报成功");
// }
if (!appOrderInService.removeById(orderIn.getRecordId())) { if (!appOrderInService.removeById(orderIn.getRecordId())) {
log.info("整箱入库完成删除入库单失败,任务:{},原因:删除入库单失败", wmsTask.getTaskId()); log.info("整箱入库完成删除入库单失败,任务:{},原因:删除入库单失败", wmsTask.getTaskId());
} }
@ -424,7 +414,6 @@ public class StackerTaskServiceImpl implements IStackerTaskService {
appVehicleService.saveOrUpdate(vehicle); appVehicleService.saveOrUpdate(vehicle);
appCommon.updateWorkingLocations(wmsTask.getDestination(), 0); appCommon.updateWorkingLocations(wmsTask.getDestination(), 0);
agvLockService.releaseAllInboundPortLocks("CR");
// 备份并删除任务 // 备份并删除任务
if (!appTaskService.removeById(wmsTask.getTaskId())) { if (!appTaskService.removeById(wmsTask.getTaskId())) {
log.info("删除入库任务失败,任务:{}", wmsTask.getTaskId()); log.info("删除入库任务失败,任务:{}", wmsTask.getTaskId());
@ -432,6 +421,24 @@ public class StackerTaskServiceImpl implements IStackerTaskService {
if (!appTaskBakService.save(wmsTask.of())) { if (!appTaskBakService.save(wmsTask.of())) {
log.info("备份入库任务失败,任务:{}", wmsTask.getTaskId()); log.info("备份入库任务失败,任务:{}", wmsTask.getTaskId());
} }
// OrderInCBReq orderInCBReq = new OrderInCBReq();
// orderInCBReq.setTaskId(orderIn.getOrderId());
// orderInCBReq.setVehicleNo(wmsTask.getVehicleId());
// orderInCBReq.setLocationId(wmsTask.getDestination());
// orderInCBReq.setResult(OrderInCBEnums.COMPLETE.getCode());
// orderInCBReq.setResultMessage("入库完成");
// int times = 0;
// MesApiResponse response = null;
// do {
// Thread.sleep(15000L * times);
// response = externalApiService.invokeOrderInCB(orderInCBReq);
// times++;
// } while (response.getCode() != 0 && times <= 10);
// if (response.getCode() != 0) {
// log.error("[wms]上报失败");
// } else {
// log.info("[wms]上报成功");
// }
} }
} }
@ -449,16 +456,14 @@ public class StackerTaskServiceImpl implements IStackerTaskService {
appStockService.update(new LambdaUpdateWrapper<TAppStock>() appStockService.update(new LambdaUpdateWrapper<TAppStock>()
.in(TAppStock::getStockId, thisVehicleStocks.stream().map(TAppStock::getStockId).toList()) .in(TAppStock::getStockId, thisVehicleStocks.stream().map(TAppStock::getStockId).toList())
.set(TAppStock::getLocationId, wmsTask.getDestination()) .set(TAppStock::getLocationId, wmsTask.getDestination())
.set(TAppStock::getStockStatus, WmsStockStatusEnums.OK.getCode()) .set(TAppStock::getStockStatus, WmsStockStatusEnums.OK.getCode()));
);
appLocationService.update(new LambdaUpdateWrapper<TAppLocation>() appLocationService.update(new LambdaUpdateWrapper<TAppLocation>()
.eq(TAppLocation::getLocationId, wmsTask.getOrigin()) .eq(TAppLocation::getLocationId, wmsTask.getOrigin())
.set(TAppLocation::getIsOccupy, WmsLocationOccupyStatusEnums.EMPTY.getCode()) .set(TAppLocation::getIsOccupy, WmsLocationOccupyStatusEnums.EMPTY.getCode())
.set(TAppLocation::getVehicleId, "")); .set(TAppLocation::getVehicleId, ""));
appVehicleService.update(new LambdaUpdateWrapper<TAppVehicle>() appVehicleService.update(new LambdaUpdateWrapper<TAppVehicle>()
.eq(TAppVehicle::getVehicleId, wmsTask.getVehicleId()) .eq(TAppVehicle::getVehicleId, wmsTask.getVehicleId())
.set(TAppVehicle::getLocationId, wmsTask.getDestination()) .set(TAppVehicle::getLocationId, wmsTask.getDestination()));
);
appCommon.updateWorkingLocations(wmsTask.getDestination(), 0); appCommon.updateWorkingLocations(wmsTask.getDestination(), 0);
appCommon.updateWorkingLocations(wmsTask.getOrigin(), 0); appCommon.updateWorkingLocations(wmsTask.getOrigin(), 0);
appTaskService.removeById(wmsTask.getTaskId()); appTaskService.removeById(wmsTask.getTaskId());
@ -482,7 +487,8 @@ public class StackerTaskServiceImpl implements IStackerTaskService {
// 5. 添加出库记录 // 5. 添加出库记录
// 根据载具号map一下 // 根据载具号map一下
Map<String, List<TAppTask>> vehicleIdToTaskMap = stackerOutTasks.stream() Map<String, List<TAppTask>> vehicleIdToTaskMap = stackerOutTasks.stream()
.filter(outTask -> Objects.equals(outTask.getTaskType(), WmsTaskTypeEnums.OUT.getCode()) && Objects.equals(outTask.getTaskStatus(), WmsStackerTaskStatusEnums.FINISH.getCode())) .filter(outTask -> Objects.equals(outTask.getTaskType(), WmsTaskTypeEnums.OUT.getCode())
&& Objects.equals(outTask.getTaskStatus(), WmsStackerTaskStatusEnums.FINISH.getCode()))
.collect(Collectors.groupingBy(TAppTask::getVehicleId)); .collect(Collectors.groupingBy(TAppTask::getVehicleId));
for (String vehicleId : vehicleIdToTaskMap.keySet()) { for (String vehicleId : vehicleIdToTaskMap.keySet()) {
// 查询当前载具的数据 // 查询当前载具的数据
@ -515,7 +521,6 @@ public class StackerTaskServiceImpl implements IStackerTaskService {
.set(TAppStock::getStockStatus, WmsStockStatusEnums.OUTED.getCode()) .set(TAppStock::getStockStatus, WmsStockStatusEnums.OUTED.getCode())
.set(TAppStock::getLocationId, "") .set(TAppStock::getLocationId, "")
.eq(TAppStock::getVehicleId, vehicleId)); .eq(TAppStock::getVehicleId, vehicleId));
agvLockService.releaseAllInboundPortLocks("CR");
// 当前载具的任务列表 // 当前载具的任务列表
List<TAppTask> thisVehicleOutTasks = vehicleIdToTaskMap.get(vehicleId); List<TAppTask> thisVehicleOutTasks = vehicleIdToTaskMap.get(vehicleId);
if (thisVehicleOutTasks.isEmpty()) { if (thisVehicleOutTasks.isEmpty()) {

View File

@ -21,7 +21,6 @@ import com.wms_main.model.po.TAppStock;
import com.wms_main.repository.utils.StringUtils; import com.wms_main.repository.utils.StringUtils;
import com.wms_main.repository.utils.UUIDUtils; import com.wms_main.repository.utils.UUIDUtils;
import com.wms_main.service.api.IWcsApiService; import com.wms_main.service.api.IWcsApiService;
import com.wms_main.service.business.IAgvLockService;
import com.wms_main.service.controller.IMyWmsControllerService; import com.wms_main.service.controller.IMyWmsControllerService;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
@ -39,7 +38,6 @@ public class MyWmsControllerServiceImpl implements IMyWmsControllerService {
private final ITAppOrderOutService appOrderOutService; private final ITAppOrderOutService appOrderOutService;
private final ITAppStockService appStockService; private final ITAppStockService appStockService;
private final ITAppLocationService appLocationService; private final ITAppLocationService appLocationService;
private final IAgvLockService agvLockService;
private final IWcsApiService wcsApiService; private final IWcsApiService wcsApiService;
@Override @Override
@ -181,17 +179,6 @@ public class MyWmsControllerServiceImpl implements IMyWmsControllerService {
return MyWmsResponse.error("WCS系统查询失败", false); return MyWmsResponse.error("WCS系统查询失败", false);
} }
Boolean wcsAllow = wcsResponse.getData().isAllowAction();
if (!wcsAllow) {
return MyWmsResponse.error("WCS系统不允许入库", false);
}
// 3. 检查agvLock服务获取wms状态
Boolean wmsAllow = agvLockService.canFeedToInboundPort("CR");
if (!wmsAllow) {
return MyWmsResponse.error("入库口锁定中", false);
}
return MyWmsResponse.success(true); return MyWmsResponse.success(true);
} catch (Exception e) { } catch (Exception e) {
return MyWmsResponse.error("系统异常,请稍后重试", false); return MyWmsResponse.error("系统异常,请稍后重试", false);
@ -207,17 +194,6 @@ public class MyWmsControllerServiceImpl implements IMyWmsControllerService {
return MyWmsResponse.error("WCS系统查询失败", false); return MyWmsResponse.error("WCS系统查询失败", false);
} }
Boolean wcsAllow = wcsResponse.getData().isAllowAction();
if (!wcsAllow) {
return MyWmsResponse.error("WCS系统不允许出库", false);
}
// 2. 检查agvLock服务获取wms状态 (使用CR口)
Boolean wmsAllow = agvLockService.canFeedToInboundPort("CR");
if (!wmsAllow) {
return MyWmsResponse.error("出库口锁定中", false);
}
return MyWmsResponse.success(true); return MyWmsResponse.success(true);
} catch (Exception e) { } catch (Exception e) {
return MyWmsResponse.error("系统异常,请稍后重试", false); return MyWmsResponse.error("系统异常,请稍后重试", false);

View File

@ -0,0 +1,97 @@
package com.wms_main.service.quartz_job.job_executor;
import java.time.LocalDateTime;
import java.util.List;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.wms_main.constant.enums.wms.OrderStatusEnum;
import com.wms_main.constant.enums.wms.WmsStackerTaskStatusEnums;
import com.wms_main.constant.enums.wms.WmsTaskTypeEnums;
import com.wms_main.dao.ITAppOrderInService;
import com.wms_main.dao.ITAppTaskService;
import com.wms_main.model.po.TAppLocation;
import com.wms_main.model.po.TAppOrderIn;
import com.wms_main.model.po.TAppTask;
import com.wms_main.repository.utils.UUIDUtils;
import com.wms_main.service.business.IStackerTaskService;
import org.quartz.DisallowConcurrentExecution;
import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.PersistJobDataAfterExecution;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
@Slf4j
@PersistJobDataAfterExecution
// 以下注解用于实现fixed_delay
@DisallowConcurrentExecution
@RequiredArgsConstructor
public class MyInExecutor implements Job {
private final ITAppOrderInService appOrderInService;
private final IStackerTaskService stackerTaskService;
private final ITAppTaskService appWmsTaskService;
private static String ORIGIN = "CR";
@Override
public void execute(JobExecutionContext context) {
processInOrders();
}
private void processInOrders() {
List<TAppOrderIn> orders = appOrderInService.list(
new LambdaQueryWrapper<TAppOrderIn>()
.eq(TAppOrderIn::getOrderStatus, OrderStatusEnum.CREATE.getCode()));
orders.forEach(this::processSingleOrder);
}
private void processSingleOrder(TAppOrderIn orderIn) {
if (orderIn == null) {
return;
}
/* 查找可用库位 */
TAppLocation useLocation = stackerTaskService.requestOneLocation(null, orderIn.getVehicleNo());
if (useLocation == null) {
log.error("暂没有可以直接使用的库位,因为存在互锁的库位,请等待当前任务都执行完成后再试");
return;
}
TAppTask newInTask = appWmsTaskService.getOne(new LambdaQueryWrapper<TAppTask>()
.eq(TAppTask::getVehicleId, orderIn.getVehicleNo())
.eq(TAppTask::getTaskType, WmsTaskTypeEnums.IN.getCode()));
if (newInTask != null) {
newInTask.setTaskStatus(WmsStackerTaskStatusEnums.WAIT.getCode());
newInTask.setDestination(useLocation.getLocationId());
newInTask.setTaskGroup(orderIn.getOrderId());
if (!appWmsTaskService.updateById(newInTask)) {
log.error("生成任务失败,无法插入新的入库任务");
return;
}
} else {
newInTask = new TAppTask();
newInTask.setTaskId(UUIDUtils.getNewUUID());
newInTask.setTaskGroup(orderIn.getOrderId());
newInTask.setTaskType(WmsTaskTypeEnums.IN.getCode());
newInTask.setTaskStatus(WmsStackerTaskStatusEnums.WAIT.getCode());
newInTask.setOrigin(ORIGIN);
newInTask.setDestination(useLocation.getLocationId());
newInTask.setCreateTime(LocalDateTime.now());
newInTask.setOpUser("wcs");
newInTask.setVehicleId(orderIn.getVehicleNo());
newInTask.setTaskPriority(1);
if (!appWmsTaskService.save(newInTask)) {
log.error("生成任务失败,无法插入新的入库任务");
return;
}
}
appOrderInService.update(
new LambdaUpdateWrapper<TAppOrderIn>()
.eq(TAppOrderIn::getRecordId, orderIn.getRecordId())
.set(TAppOrderIn::getOrderStatus, OrderStatusEnum.RUNNING.getCode())
.set(TAppOrderIn::getUpdateTime, LocalDateTime.now()));
return;
}
}

View File

@ -4,7 +4,6 @@ import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.wms_main.constant.enums.wcs.WcsApiResponseCodeEnums; import com.wms_main.constant.enums.wcs.WcsApiResponseCodeEnums;
import com.wms_main.constant.enums.wcs.WcsStackerTaskStatusEnums; import com.wms_main.constant.enums.wcs.WcsStackerTaskStatusEnums;
import com.wms_main.constant.enums.wcs.WcsStackerTaskTypeEnums;
import com.wms_main.constant.enums.wms.WmsStackerTaskStatusEnums; import com.wms_main.constant.enums.wms.WmsStackerTaskStatusEnums;
import com.wms_main.dao.ITAppTaskService; import com.wms_main.dao.ITAppTaskService;
import com.wms_main.dao.ITAppWcsTaskService; import com.wms_main.dao.ITAppWcsTaskService;
@ -15,7 +14,6 @@ import com.wms_main.model.po.TAppTask;
import com.wms_main.model.po.TAppWcsTask; import com.wms_main.model.po.TAppWcsTask;
import com.wms_main.repository.utils.StringUtils; import com.wms_main.repository.utils.StringUtils;
import com.wms_main.service.api.IWcsApiService; import com.wms_main.service.api.IWcsApiService;
import com.wms_main.service.business.IAgvLockService;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.quartz.*; import org.quartz.*;
@ -43,11 +41,6 @@ public class WcsStackerTaskSender implements Job {
* Wcs接口服务 * Wcs接口服务
*/ */
private final IWcsApiService wcsApiService; private final IWcsApiService wcsApiService;
/**
* AGV锁定服务
*/
private final IAgvLockService agvLockService;
/** /**
* 运行定时任务 * 运行定时任务
* 向Wcs发送堆垛机任务 * 向Wcs发送堆垛机任务
@ -56,10 +49,10 @@ public class WcsStackerTaskSender implements Job {
*/ */
@Override @Override
public void execute(JobExecutionContext jobExecutionContext) { public void execute(JobExecutionContext jobExecutionContext) {
if (appWcsTaskService.exists(new LambdaQueryWrapper<TAppWcsTask>().eq(TAppWcsTask::getWcsTaskStatus, // if (appWcsTaskService.exists(new LambdaQueryWrapper<TAppWcsTask>().eq(TAppWcsTask::getWcsTaskStatus,
WcsStackerTaskStatusEnums.WAIT.getCode()))) { // WcsStackerTaskStatusEnums.WAIT.getCode()))) {
return; // return;
} // }
// 查询到所有的待下发的wcsTask并按优先级排序 // 查询到所有的待下发的wcsTask并按优先级排序
List<TAppWcsTask> waitSendWcsTaskList = appWcsTaskService.list( List<TAppWcsTask> waitSendWcsTaskList = appWcsTaskService.list(
new LambdaQueryWrapper<TAppWcsTask>() new LambdaQueryWrapper<TAppWcsTask>()
@ -72,12 +65,6 @@ public class WcsStackerTaskSender implements Job {
waitSendWcsTaskList.sort((task1, task2) -> Integer.compare(task2.getTaskPriority(), task1.getTaskPriority())); waitSendWcsTaskList.sort((task1, task2) -> Integer.compare(task2.getTaskPriority(), task1.getTaskPriority()));
// 发送任务 // 发送任务
TAppWcsTask wcsTask = waitSendWcsTaskList.getFirst(); TAppWcsTask wcsTask = waitSendWcsTaskList.getFirst();
if (wcsTask.getWcsTaskType().equals(WcsStackerTaskTypeEnums.OUT.getCode())) {
Boolean wmsAllow = agvLockService.canFeedToInboundPort(wcsTask.getDestination());
if (!wmsAllow) {
return;
}
}
// 生成请求 // 生成请求
WcsStackerTaskRequest request = new WcsStackerTaskRequest( WcsStackerTaskRequest request = new WcsStackerTaskRequest(
wcsTask.getWcsTaskId(), wcsTask.getWcsTaskId(),
@ -101,19 +88,6 @@ public class WcsStackerTaskSender implements Job {
.set(TAppTask::getTaskStatus, WmsStackerTaskStatusEnums.SEND.getCode()) .set(TAppTask::getTaskStatus, WmsStackerTaskStatusEnums.SEND.getCode())
.eq(TAppTask::getWcsTaskId, wcsTask.getWcsTaskId())); .eq(TAppTask::getWcsTaskId, wcsTask.getWcsTaskId()));
if (wcsTask.getWcsTaskType().equals(WcsStackerTaskTypeEnums.OUT.getCode())) {
try {
agvLockService.lockInboundPort("AGV", wcsTask.getDestination());
} catch (Exception e) {
log.error("任务发送成功后锁定{}口失败任务ID: {}", wcsTask.getDestination(), wcsTask.getWcsTaskId());
}
} else if (wcsTask.getWcsTaskType().equals(WcsStackerTaskTypeEnums.IN.getCode())) {
try {
agvLockService.lockInboundPort("AGV", wcsTask.getOrigin());
} catch (Exception e) {
log.error("任务发送成功后锁定{}口失败任务ID: {}", wcsTask.getOrigin(), wcsTask.getWcsTaskId());
}
}
} else { } else {
log.error("堆垛机任务发送失败,请求{},响应信息{}。", StringUtils.objectToString(request), log.error("堆垛机任务发送失败,请求{},响应信息{}。", StringUtils.objectToString(request),
StringUtils.objectToString(wcsResponse)); StringUtils.objectToString(wcsResponse));

View File

@ -23,7 +23,7 @@ spring:
# 服务配置 # 服务配置
server: server:
port: 12315 port: 12325
servlet: servlet:
context-path: / context-path: /

View File

@ -8,7 +8,7 @@ Content-Type: application/json
{ {
"taskId": "testOrderId1", "taskId": "testOrderId1",
"vehicleNo": "1003" "vehicleNo": "1001"
} }
### 2. 出库订单接口 ### 2. 出库订单接口
@ -16,8 +16,8 @@ POST {{baseUrl}}/mywms/orderOut
Content-Type: application/json Content-Type: application/json
{ {
"taskId": "testOrderId3", "taskId": "testOrderId2",
"vehicleNo": "1001" "vehicleNo": "1002"
} }
### 3. 发送任务结果 - 任务完成 ### 3. 发送任务结果 - 任务完成
@ -25,7 +25,7 @@ POST {{baseUrl}}/wms/task/sendTaskResult
Content-Type: application/json Content-Type: application/json
{ {
"taskId": "1757666162511010000", "taskId": "1758595357068010000",
"taskStatus": 100, "taskStatus": 100,
"vehicleNo": "1007", "vehicleNo": "1007",
"destination": "C1", "destination": "C1",
@ -51,7 +51,15 @@ POST {{baseUrl}}/mywms/cancelOrderIn
Content-Type: application/json Content-Type: application/json
{ {
"vehicleNo": "1003" "vehicleNo": "1005"
}
### 8. AGVDone
POST {{baseUrl}}/mywms/agvDone
Content-Type: application/json
{
"taskId": "testOrderId1"
} }
### 测试数据说明 ### 测试数据说明

View File

@ -5,6 +5,7 @@ import lombok.Getter;
@Getter @Getter
public enum OrderStatusEnum { public enum OrderStatusEnum {
TEMP(-1, "暂存"),
CREATE(0, "创建"), CREATE(0, "创建"),
RUNNING(1, "运行中"), RUNNING(1, "运行中"),
COMPLETE(2, "完成"), COMPLETE(2, "完成"),

View File

@ -1,5 +1,6 @@
package com.wms_main.controller.mywms; package com.wms_main.controller.mywms;
import com.wms_main.model.dto.request.mywms.AGVDoneReq;
import com.wms_main.model.dto.request.mywms.OrderInCancel; import com.wms_main.model.dto.request.mywms.OrderInCancel;
import com.wms_main.model.dto.request.mywms.OrderInReq; import com.wms_main.model.dto.request.mywms.OrderInReq;
import com.wms_main.model.dto.request.mywms.OrderOutReq; import com.wms_main.model.dto.request.mywms.OrderOutReq;
@ -49,8 +50,8 @@ public class MyWmsController {
} }
@PostMapping("/agvDone") @PostMapping("/agvDone")
public MyWmsResponse<Object> agvDone() { public MyWmsResponse<Object> agvDone(@RequestBody AGVDoneReq request) {
return myWmsControllerService.agvDone(); return myWmsControllerService.agvDone(request);
} }
@PostMapping("/cancelOrderIn") @PostMapping("/cancelOrderIn")

View File

@ -0,0 +1,11 @@
package com.wms_main.model.dto.request.mywms;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Getter;
import lombok.Setter;
@Getter
@Setter
public class AGVDoneReq {
@JsonProperty("taskId")
private String taskId;
}

View File

@ -1,109 +0,0 @@
package com.wms_main.service.business;
import com.wms_main.model.po.TAppAgvLock;
/**
* AGV资源锁定服务接口
* 管理入库口和出库口的AGV设备互锁机制
*/
public interface IAgvLockService {
/**
* AGV就位并放货后锁定入库口
* @param agvId AGV设备ID
* @param inboundPort 入库口编号
* @return 锁定结果成功返回锁定记录失败返回null
*/
TAppAgvLock lockInboundPort(String agvId, String inboundPort);
/**
* 检查入库口是否可以上料MES系统调用
* @param inboundPort 入库口编号
* @return 是否可以上料
*/
boolean canFeedToInboundPort(String inboundPort);
/**
* 获取当前入库口处理中的任务数量
* @param inboundPort 入库口编号
* @return 处理中的任务数量
*/
int getProcessingTaskCount(String inboundPort);
/**
* 获取入库口状态描述
* @param inboundPort 入库口编号
* @return 状态描述空闲/占用
*/
String getInboundPortStatus(String inboundPort);
/**
* 清理超时锁定
* @return 清理的记录数
*/
int cleanTimeoutLocks();
/**
* 释放指定入库口的所有活动锁定
* @param inboundPort 入库口编号
* @return 释放的锁定数量
*/
int releaseAllInboundPortLocks(String inboundPort);
// ========== 出库口锁定相关方法 ==========
/**
* AGV到达出库口后锁定出库口
* @param agvId AGV设备ID
* @param outboundPort 出库口编号
* @return 锁定结果成功返回锁定记录失败返回null
*/
TAppAgvLock lockOutboundPort(String agvId, String outboundPort);
/**
* 检查出库口是否可以出料MES系统调用
* @param outboundPort 出库口编号
* @return 是否可以出料
*/
boolean canFeedToOutboundPort(String outboundPort);
/**
* 获取当前出库口处理中的任务数量
* @param outboundPort 出库口编号
* @return 处理中的任务数量
*/
int getProcessingOutTaskCount(String outboundPort);
/**
* 获取出库口状态描述
* @param outboundPort 出库口编号
* @return 状态描述空闲/占用
*/
String getOutboundPortStatus(String outboundPort);
/**
* 释放指定出库口的所有活动锁定
* @param outboundPort 出库口编号
* @return 释放的锁定数量
*/
int releaseAllOutboundPortLocks(String outboundPort);
// ========== 通用锁定方法 ==========
/**
* 通用资源锁定方法
* @param agvId AGV设备ID
* @param stationCode 站台编号R1=入库口C1=出库口
* @param taskType 任务类型1=入库2=出库
* @return 锁定结果成功返回锁定记录失败返回null
*/
TAppAgvLock lockStation(String agvId, String stationCode, Integer taskType);
/**
* 通用资源解锁方法
* @param stationCode 站台编号R1=入库口C1=出库口
* @param taskType 任务类型1=入库2=出库
* @return 释放的锁定数量
*/
int releaseStationLocks(String stationCode, Integer taskType);
}

View File

@ -1,442 +0,0 @@
package com.wms_main.service.business.serviceImpl;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.wms_main.constant.enums.wms.WmsAgvLockEnums;
import com.wms_main.dao.ITAppAgvLockService;
import com.wms_main.dao.ITAppTaskService;
import com.wms_main.model.po.TAppAgvLock;
import com.wms_main.model.po.TAppTask;
import com.wms_main.constant.enums.wms.WmsTaskTypeEnums;
import com.wms_main.constant.enums.wms.WmsStackerTaskStatusEnums;
import com.wms_main.repository.utils.StringUtils;
import com.wms_main.repository.utils.UUIDUtils;
import com.wms_main.service.business.IAgvLockService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Objects;
/**
* AGV资源锁定服务实现
* 管理入库口和出库口的AGV设备互锁机制
*/
@Service
@RequiredArgsConstructor
@Slf4j
public class AgvLockServiceImpl implements IAgvLockService {
private final ITAppAgvLockService agvLockService;
private final ITAppTaskService appTaskService;
private static final String DEFAULT_INBOUND_PORT = "R1"; // 默认入库口
private static final String DEFAULT_OUTBOUND_PORT = "C1"; // 默认出库口
private static final int DEFAULT_TIMEOUT_SECONDS = 600; // 默认超时时间10分钟
@Override
@Transactional
public TAppAgvLock lockInboundPort(String agvId, String inboundPort) {
if (StringUtils.isEmpty(agvId)) {
log.warn("AGV ID为空");
return null;
}
// 使用默认入库口如果未指定
if (StringUtils.isEmpty(inboundPort)) {
inboundPort = DEFAULT_INBOUND_PORT;
}
// 清理超时锁定
cleanTimeoutLocks();
// 检查入库口是否已被占用
List<TAppAgvLock> existingLocks = agvLockService.list(new LambdaQueryWrapper<TAppAgvLock>().eq(TAppAgvLock::getFeedStation, inboundPort));
if (existingLocks == null || existingLocks.isEmpty()) {
return createInboundPortLock(agvId, inboundPort);
} else {
agvLockService.update(
new LambdaUpdateWrapper<TAppAgvLock>()
.eq(TAppAgvLock::getFeedStation, inboundPort)
.eq(TAppAgvLock::getLockStatus, WmsAgvLockEnums.AVAILABLE.getCode())
.set(TAppAgvLock::getLockStatus, WmsAgvLockEnums.LOCK.getCode())
.set(TAppAgvLock::getLockTime, LocalDateTime.now())
.set(TAppAgvLock::getRemark, "AGV就位并放货锁定入库口")
);
return null;
}
}
@Override
public boolean canFeedToInboundPort(String inboundPort) {
// 使用默认入库口如果未指定
if (StringUtils.isEmpty(inboundPort)) {
inboundPort = DEFAULT_INBOUND_PORT;
}
// 清理超时锁定
cleanTimeoutLocks();
// 检查入库口是否有活动的锁定
List<TAppAgvLock> activeLocks = agvLockService.getByStation(inboundPort);
boolean hasActiveLock = activeLocks.stream()
.anyMatch(lock -> lock.getLockStatus() == 1);
if (hasActiveLock) {
log.debug("入库口 {} 当前被占用,无法上料", inboundPort);
return false;
}
// 检查是否有正在处理的入库任务
int processingTasks = getProcessingTaskCount(inboundPort);
boolean canFeed = processingTasks == 0;
log.debug("入库口 {} 可上料状态: {}, 处理中任务数: {}", inboundPort, canFeed, processingTasks);
return canFeed;
}
@Override
public int getProcessingTaskCount(String inboundPort) {
// 使用默认入库口如果未指定
if (StringUtils.isEmpty(inboundPort)) {
inboundPort = DEFAULT_INBOUND_PORT;
}
// 统计正在处理的入库任务数量包括等待运行状态的任务
List<TAppTask> processingTasks = appTaskService.list(
new LambdaQueryWrapper<TAppTask>()
.eq(TAppTask::getTaskType, WmsTaskTypeEnums.IN.getCode())
.in(TAppTask::getTaskStatus,
WmsStackerTaskStatusEnums.WAIT.getCode(),
WmsStackerTaskStatusEnums.RUN.getCode())
.like(TAppTask::getOrigin, inboundPort) // 假设任务来源包含入库口信息
);
return processingTasks.size();
}
@Override
public String getInboundPortStatus(String inboundPort) {
// 使用默认入库口如果未指定
if (StringUtils.isEmpty(inboundPort)) {
inboundPort = DEFAULT_INBOUND_PORT;
}
// 检查是否有活动锁定
List<TAppAgvLock> activeLocks = agvLockService.getByStation(inboundPort);
boolean hasActiveLock = activeLocks.stream()
.anyMatch(lock -> lock.getLockStatus() == 1);
if (hasActiveLock) {
return "占用";
}
// 检查是否有处理中的任务
int processingTasks = getProcessingTaskCount(inboundPort);
if (processingTasks > 0) {
return "占用";
}
return "空闲";
}
@Override
@Transactional
public int cleanTimeoutLocks() {
List<TAppAgvLock> timeoutLocks = agvLockService.getTimeoutLocks();
if (timeoutLocks.isEmpty()) {
return 0;
}
try {
for (TAppAgvLock lock : timeoutLocks) {
agvLockService.update(
new LambdaUpdateWrapper<TAppAgvLock>()
.eq(TAppAgvLock::getLockId, lock.getLockId())
.set(TAppAgvLock::getLockStatus, 0)
.set(TAppAgvLock::getUnlockTime, LocalDateTime.now())
.set(TAppAgvLock::getRemark, "超时自动释放")
);
log.info("释放超时锁定: AGV {} 在入库口 {}", lock.getAgvId(), lock.getFeedStation());
}
log.info("清理了 {} 个超时锁定", timeoutLocks.size());
return timeoutLocks.size();
} catch (Exception e) {
log.error("清理超时锁定失败", e);
return 0;
}
}
@Override
@Transactional
public int releaseAllInboundPortLocks(String inboundPort) {
// 使用默认入库口如果未指定
if (StringUtils.isEmpty(inboundPort)) {
inboundPort = DEFAULT_INBOUND_PORT;
}
try {
// 释放指定入库口的所有活动锁定
agvLockService.update(
new LambdaUpdateWrapper<TAppAgvLock>()
.eq(TAppAgvLock::getFeedStation, inboundPort)
.eq(TAppAgvLock::getLockStatus, WmsAgvLockEnums.LOCK.getCode())
.set(TAppAgvLock::getLockStatus, WmsAgvLockEnums.AVAILABLE.getCode())
.set(TAppAgvLock::getUnlockTime, LocalDateTime.now())
.set(TAppAgvLock::getRemark, "入库任务完成,批量释放锁定")
);
// 查询实际释放的锁定数量
List<TAppAgvLock> activeLocks = agvLockService.getByStation(inboundPort);
int releasedCount = (int) activeLocks.stream()
.filter(lock -> lock.getLockStatus() == 0)
.count();
log.info("释放入库口 {} 的所有锁定,共释放 {} 个锁定", inboundPort, releasedCount);
return releasedCount;
} catch (Exception e) {
log.error("释放入库口 {} 的所有锁定失败", inboundPort, e);
return 0;
}
}
// ========== 出库口锁定相关方法实现 ==========
@Override
@Transactional
public TAppAgvLock lockOutboundPort(String agvId, String outboundPort) {
if (StringUtils.isEmpty(agvId)) {
log.warn("AGV ID为空");
return null;
}
// 使用默认出库口如果未指定
if (StringUtils.isEmpty(outboundPort)) {
outboundPort = DEFAULT_OUTBOUND_PORT;
}
// 清理超时锁定
cleanTimeoutLocks();
// 检查出库口是否已被占用
List<TAppAgvLock> existingLocks = agvLockService.list(new LambdaQueryWrapper<TAppAgvLock>().eq(TAppAgvLock::getFeedStation, outboundPort));
if (existingLocks == null || existingLocks.isEmpty()) {
return createOutboundPortLock(agvId, outboundPort);
} else {
agvLockService.update(
new LambdaUpdateWrapper<TAppAgvLock>()
.eq(TAppAgvLock::getFeedStation, outboundPort)
.eq(TAppAgvLock::getLockStatus, WmsAgvLockEnums.AVAILABLE.getCode())
.set(TAppAgvLock::getLockStatus, WmsAgvLockEnums.LOCK.getCode())
.set(TAppAgvLock::getLockTime, LocalDateTime.now())
.set(TAppAgvLock::getRemark, "AGV就位并取货锁定出库口")
);
return null;
}
}
@Override
public boolean canFeedToOutboundPort(String outboundPort) {
// 使用默认出库口如果未指定
if (StringUtils.isEmpty(outboundPort)) {
outboundPort = DEFAULT_OUTBOUND_PORT;
}
// 清理超时锁定
cleanTimeoutLocks();
// 检查出库口是否有活动的锁定
List<TAppAgvLock> activeLocks = agvLockService.getByStation(outboundPort);
boolean hasActiveLock = activeLocks.stream()
.anyMatch(lock -> lock.getLockStatus() == 1);
if (hasActiveLock) {
log.debug("出库口 {} 当前被占用,无法出料", outboundPort);
return false;
}
// 检查是否有正在处理的出库任务
int processingTasks = getProcessingOutTaskCount(outboundPort);
boolean canFeed = processingTasks == 0;
log.debug("出库口 {} 可出料状态: {}, 处理中任务数: {}", outboundPort, canFeed, processingTasks);
return canFeed;
}
@Override
public int getProcessingOutTaskCount(String outboundPort) {
// 使用默认出库口如果未指定
if (StringUtils.isEmpty(outboundPort)) {
outboundPort = DEFAULT_OUTBOUND_PORT;
}
// 统计正在处理的出库任务数量包括等待运行状态的任务
List<TAppTask> processingTasks = appTaskService.list(
new LambdaQueryWrapper<TAppTask>()
.eq(TAppTask::getTaskType, WmsTaskTypeEnums.OUT.getCode())
.in(TAppTask::getTaskStatus,
WmsStackerTaskStatusEnums.WAIT.getCode(),
WmsStackerTaskStatusEnums.RUN.getCode())
.like(TAppTask::getDestination, outboundPort) // 假设任务目标包含出库口信息
);
return processingTasks.size();
}
@Override
public String getOutboundPortStatus(String outboundPort) {
// 使用默认出库口如果未指定
if (StringUtils.isEmpty(outboundPort)) {
outboundPort = DEFAULT_OUTBOUND_PORT;
}
// 检查是否有活动锁定
List<TAppAgvLock> activeLocks = agvLockService.getByStation(outboundPort);
boolean hasActiveLock = activeLocks.stream()
.anyMatch(lock -> lock.getLockStatus() == 1);
if (hasActiveLock) {
return "占用";
}
// 检查是否有处理中的任务
int processingTasks = getProcessingOutTaskCount(outboundPort);
if (processingTasks > 0) {
return "占用";
}
return "空闲";
}
@Override
@Transactional
public int releaseAllOutboundPortLocks(String outboundPort) {
// 使用默认出库口如果未指定
if (StringUtils.isEmpty(outboundPort)) {
outboundPort = DEFAULT_OUTBOUND_PORT;
}
try {
// 释放指定出库口的所有活动锁定
agvLockService.update(
new LambdaUpdateWrapper<TAppAgvLock>()
.eq(TAppAgvLock::getFeedStation, outboundPort)
.eq(TAppAgvLock::getLockStatus, WmsAgvLockEnums.LOCK.getCode())
.set(TAppAgvLock::getLockStatus, WmsAgvLockEnums.AVAILABLE.getCode())
.set(TAppAgvLock::getUnlockTime, LocalDateTime.now())
.set(TAppAgvLock::getRemark, "出库任务完成,批量释放锁定")
);
// 查询实际释放的锁定数量
List<TAppAgvLock> activeLocks = agvLockService.getByStation(outboundPort);
int releasedCount = (int) activeLocks.stream()
.filter(lock -> lock.getLockStatus() == 0)
.count();
log.info("释放出库口 {} 的所有锁定,共释放 {} 个锁定", outboundPort, releasedCount);
return releasedCount;
} catch (Exception e) {
log.error("释放出库口 {} 的所有锁定失败", outboundPort, e);
return 0;
}
}
// ========== 通用锁定方法实现 ==========
@Override
@Transactional
public TAppAgvLock lockStation(String agvId, String stationCode, Integer taskType) {
if (StringUtils.isEmpty(agvId) || StringUtils.isEmpty(stationCode) || Objects.isNull(taskType)) {
log.warn("锁定参数不完整: agvId={}, stationCode={}, taskType={}", agvId, stationCode, taskType);
return null;
}
if (WmsTaskTypeEnums.IN.getCode().equals(taskType)) {
return lockInboundPort(agvId, stationCode);
} else if (WmsTaskTypeEnums.OUT.getCode().equals(taskType)) {
return lockOutboundPort(agvId, stationCode);
} else {
log.warn("不支持的任务类型: {}", taskType);
return null;
}
}
@Override
@Transactional
public int releaseStationLocks(String stationCode, Integer taskType) {
if (StringUtils.isEmpty(stationCode) || Objects.isNull(taskType)) {
log.warn("解锁参数不完整: stationCode={}, taskType={}", stationCode, taskType);
return 0;
}
if (WmsTaskTypeEnums.IN.getCode().equals(taskType)) {
return releaseAllInboundPortLocks(stationCode);
} else if (WmsTaskTypeEnums.OUT.getCode().equals(taskType)) {
return releaseAllOutboundPortLocks(stationCode);
} else {
log.warn("不支持的任务类型: {}", taskType);
return 0;
}
}
// ========== 私有方法 ==========
/**
* 创建入库口锁定记录
*/
private TAppAgvLock createInboundPortLock(String agvId, String inboundPort) {
TAppAgvLock lock = new TAppAgvLock();
lock.setLockId(UUIDUtils.getNewUUID());
lock.setAgvId(agvId);
lock.setFeedStation(inboundPort);
lock.setLockStatus(1);
lock.setLockType("INBOUND_PORT_LOCK");
lock.setPriority(1);
lock.setQueuePosition(1);
lock.setLockTime(LocalDateTime.now());
lock.setTimeoutSeconds(DEFAULT_TIMEOUT_SECONDS);
lock.setCreateTime(LocalDateTime.now());
lock.setUpdateTime(LocalDateTime.now());
lock.setRemark("AGV就位并放货锁定入库口");
if (agvLockService.save(lock)) {
log.info("AGV {} 成功锁定入库口 {}", agvId, inboundPort);
return lock;
}
log.error("AGV {} 锁定入库口 {} 失败", agvId, inboundPort);
return null;
}
/**
* 创建出库口锁定记录
*/
private TAppAgvLock createOutboundPortLock(String agvId, String outboundPort) {
TAppAgvLock lock = new TAppAgvLock();
lock.setLockId(UUIDUtils.getNewUUID());
lock.setAgvId(agvId);
lock.setFeedStation(outboundPort);
lock.setLockStatus(1);
lock.setLockType("OUTBOUND_PORT_LOCK");
lock.setPriority(1);
lock.setQueuePosition(1);
lock.setLockTime(LocalDateTime.now());
lock.setTimeoutSeconds(DEFAULT_TIMEOUT_SECONDS);
lock.setCreateTime(LocalDateTime.now());
lock.setUpdateTime(LocalDateTime.now());
lock.setRemark("AGV就位并取货锁定出库口");
if (agvLockService.save(lock)) {
log.info("AGV {} 成功锁定出库口 {}", agvId, outboundPort);
return lock;
}
log.error("AGV {} 锁定出库口 {} 失败", agvId, outboundPort);
return null;
}
}

View File

@ -15,7 +15,6 @@ import com.wms_main.repository.utils.ConvertUtils;
import com.wms_main.repository.utils.StringUtils; import com.wms_main.repository.utils.StringUtils;
import com.wms_main.repository.utils.UUIDUtils; import com.wms_main.repository.utils.UUIDUtils;
import com.wms_main.service.api.IExternalApiService; import com.wms_main.service.api.IExternalApiService;
import com.wms_main.service.business.IAgvLockService;
import com.wms_main.service.business.IStackerTaskService; import com.wms_main.service.business.IStackerTaskService;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
@ -68,8 +67,6 @@ public class StackerTaskServiceImpl implements IStackerTaskService {
private final ITAppOrderOutService appOrderOutService; private final ITAppOrderOutService appOrderOutService;
private final IExternalApiService externalApiService; private final IExternalApiService externalApiService;
private final IAgvLockService agvLockService;
/** /**
* 业务通用 * 业务通用
*/ */
@ -455,7 +452,6 @@ public class StackerTaskServiceImpl implements IStackerTaskService {
appVehicleService.saveOrUpdate(vehicle); appVehicleService.saveOrUpdate(vehicle);
appCommon.updateWorkingLocations(wmsTask.getDestination(), 0); appCommon.updateWorkingLocations(wmsTask.getDestination(), 0);
agvLockService.releaseStationLocks("R1", WmsTaskTypeEnums.IN.getCode());
// 备份并删除任务 // 备份并删除任务
if (!appTaskService.removeById(wmsTask.getTaskId())) { if (!appTaskService.removeById(wmsTask.getTaskId())) {
log.info("删除入库任务失败,任务:{}", wmsTask.getTaskId()); log.info("删除入库任务失败,任务:{}", wmsTask.getTaskId());
@ -571,7 +567,6 @@ public class StackerTaskServiceImpl implements IStackerTaskService {
.set(TAppStock::getStockStatus, WmsStockStatusEnums.OUTED.getCode()) .set(TAppStock::getStockStatus, WmsStockStatusEnums.OUTED.getCode())
.set(TAppStock::getLocationId, "") .set(TAppStock::getLocationId, "")
.eq(TAppStock::getVehicleId, vehicleId)); .eq(TAppStock::getVehicleId, vehicleId));
agvLockService.releaseStationLocks("C1", WmsTaskTypeEnums.OUT.getCode());
// 当前载具的任务列表 // 当前载具的任务列表
List<TAppTask> thisVehicleOutTasks = vehicleIdToTaskMap.get(vehicleId); List<TAppTask> thisVehicleOutTasks = vehicleIdToTaskMap.get(vehicleId);
if (thisVehicleOutTasks.isEmpty()) { if (thisVehicleOutTasks.isEmpty()) {

View File

@ -1,5 +1,6 @@
package com.wms_main.service.controller; package com.wms_main.service.controller;
import com.wms_main.model.dto.request.mywms.AGVDoneReq;
import com.wms_main.model.dto.request.mywms.OrderInCancel; import com.wms_main.model.dto.request.mywms.OrderInCancel;
import com.wms_main.model.dto.request.mywms.OrderInReq; import com.wms_main.model.dto.request.mywms.OrderInReq;
import com.wms_main.model.dto.request.mywms.OrderOutReq; import com.wms_main.model.dto.request.mywms.OrderOutReq;
@ -22,5 +23,5 @@ public interface IMyWmsControllerService {
String cancelOrderIn(OrderInCancel request); String cancelOrderIn(OrderInCancel request);
MyWmsResponse<Object> agvDone(); MyWmsResponse<Object> agvDone(AGVDoneReq request);
} }

View File

@ -30,7 +30,6 @@ import com.wms_main.model.po.TAppWcsTask;
import com.wms_main.repository.utils.StringUtils; import com.wms_main.repository.utils.StringUtils;
import com.wms_main.repository.utils.UUIDUtils; import com.wms_main.repository.utils.UUIDUtils;
import com.wms_main.service.api.IWcsApiService; import com.wms_main.service.api.IWcsApiService;
import com.wms_main.service.business.IAgvLockService;
import com.wms_main.service.controller.IMyWmsControllerService; import com.wms_main.service.controller.IMyWmsControllerService;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
@ -47,7 +46,6 @@ public class MyWmsControllerServiceImpl implements IMyWmsControllerService {
private final ITAppOrderInService appOrderInService; private final ITAppOrderInService appOrderInService;
private final ITAppOrderOutService appOrderOutService; private final ITAppOrderOutService appOrderOutService;
private final ITAppStockService appStockService; private final ITAppStockService appStockService;
private final IAgvLockService agvLockService;
private final IWcsApiService wcsApiService; private final IWcsApiService wcsApiService;
private final ITAppTaskService appTaskService; private final ITAppTaskService appTaskService;
private final ITAppWcsTaskService appWcsTaskService; private final ITAppWcsTaskService appWcsTaskService;
@ -63,14 +61,6 @@ public class MyWmsControllerServiceImpl implements IMyWmsControllerService {
return OrderResponse.error("参数错误"); return OrderResponse.error("参数错误");
} }
// 检查入库口是否可用
String inboundPort = "R1"; // 默认入库口
boolean canFeed = agvLockService.canFeedToInboundPort(inboundPort);
if (!canFeed) {
String portStatus = agvLockService.getInboundPortStatus(inboundPort);
return OrderResponse.error("入库口当前" + portStatus + ",无法生成入库订单,请稍后重试");
}
// 校验是否存在相同的入库单 // 校验是否存在相同的入库单
List<TAppOrderIn> withTaskId = appOrderInService.getWithTaskId(request.getTaskId()); List<TAppOrderIn> withTaskId = appOrderInService.getWithTaskId(request.getTaskId());
if (withTaskId == null) { if (withTaskId == null) {
@ -91,7 +81,7 @@ public class MyWmsControllerServiceImpl implements IMyWmsControllerService {
orderIn.setVehicleNo(request.getVehicleNo()); orderIn.setVehicleNo(request.getVehicleNo());
orderIn.setInStand("R1"); orderIn.setInStand("R1");
orderIn.setRequestUser("wms"); orderIn.setRequestUser("wms");
orderIn.setOrderStatus(OrderStatusEnum.CREATE.getCode()); orderIn.setOrderStatus(OrderStatusEnum.TEMP.getCode());
orderIn.setCreateTime(LocalDateTime.now()); orderIn.setCreateTime(LocalDateTime.now());
orderIn.setUpdateTime(LocalDateTime.now()); orderIn.setUpdateTime(LocalDateTime.now());
if (!appOrderInService.save(orderIn)) { if (!appOrderInService.save(orderIn)) {
@ -209,11 +199,6 @@ public class MyWmsControllerServiceImpl implements IMyWmsControllerService {
if (!wcsAllow) { if (!wcsAllow) {
return MyWmsResponse.error("WCS系统不允许AGV上料", false); return MyWmsResponse.error("WCS系统不允许AGV上料", false);
} }
Boolean wmsAllow = agvLockService.canFeedToInboundPort("R1");
if (!wmsAllow) {
return MyWmsResponse.error("入库口锁定中", false);
}
return MyWmsResponse.success(true); return MyWmsResponse.success(true);
} catch (Exception e) { } catch (Exception e) {
return MyWmsResponse.error("系统异常,请稍后重试", null); return MyWmsResponse.error("系统异常,请稍后重试", null);
@ -222,7 +207,6 @@ public class MyWmsControllerServiceImpl implements IMyWmsControllerService {
private MyWmsResponse<Boolean> queryStandStatusOut(QueryStandStatusReq request) { private MyWmsResponse<Boolean> queryStandStatusOut(QueryStandStatusReq request) {
try { try {
// 1. 调用wcs.canFeed检查wcs状态 (使用R1口)
WcsApiResponse<WcsCanFeedResponse> wcsResponse = wcsApiService WcsApiResponse<WcsCanFeedResponse> wcsResponse = wcsApiService
.queryStandStatus(new WcsQueryStandStatusRequest(request.getStandType())); .queryStandStatus(new WcsQueryStandStatusRequest(request.getStandType()));
if (wcsResponse == null || wcsResponse.getData() == null) { if (wcsResponse == null || wcsResponse.getData() == null) {
@ -234,12 +218,6 @@ public class MyWmsControllerServiceImpl implements IMyWmsControllerService {
return MyWmsResponse.error("WCS系统不允许AGV取货", false); return MyWmsResponse.error("WCS系统不允许AGV取货", false);
} }
// 2. 检查agvLock服务获取wms状态 (使用R1口)
Boolean wmsAllow = agvLockService.canFeedToInboundPort("C1");
if (!wmsAllow) {
return MyWmsResponse.error("出库口锁定中", false);
}
return MyWmsResponse.success(true); return MyWmsResponse.success(true);
} catch (Exception e) { } catch (Exception e) {
return MyWmsResponse.error("系统异常,请稍后重试", false); return MyWmsResponse.error("系统异常,请稍后重试", false);
@ -247,7 +225,27 @@ public class MyWmsControllerServiceImpl implements IMyWmsControllerService {
} }
@Override @Override
public MyWmsResponse<Object> agvDone() { public MyWmsResponse<Object> agvDone(AGVDoneReq request) {
if (StringUtils.isEmpty(request.getTaskId())) {
return agvDoneOut();
} else {
return agvDoneIn(request);
}
}
private MyWmsResponse<Object> agvDoneIn(AGVDoneReq request) {
LambdaUpdateWrapper<TAppOrderIn> updateWrapper = new LambdaUpdateWrapper<TAppOrderIn>()
.eq(TAppOrderIn::getOrderId, request.getTaskId())
.eq(TAppOrderIn::getOrderStatus, OrderStatusEnum.TEMP.getCode())
.set(TAppOrderIn::getOrderStatus, OrderStatusEnum.CREATE.getCode());
if (appOrderInService.update(updateWrapper)) {
return MyWmsResponse.success();
} else {
return MyWmsResponse.error("更新订单状态失败", null);
}
}
private MyWmsResponse<Object> agvDoneOut() {
try { try {
BaseWcsApiResponse wcsResponse = wcsApiService.agvDone(); BaseWcsApiResponse wcsResponse = wcsApiService.agvDone();
if (wcsResponse == null) { if (wcsResponse == null) {
@ -284,8 +282,10 @@ public class MyWmsControllerServiceImpl implements IMyWmsControllerService {
if (locationList != null && locationList.size() > 0) { if (locationList != null && locationList.size() > 0) {
location = locationList.getFirst(); location = locationList.getFirst();
} }
if (location != null && !appStockService.exists(new LambdaQueryWrapper<TAppStock>().eq(StringUtils.isNotEmpty(vehicleNo), if (location != null && !appStockService.exists(new LambdaQueryWrapper<TAppStock>()
TAppStock::getVehicleId, vehicleNo).eq(TAppStock::getStockStatus, WmsStockStatusEnums.OK.getCode()))) { .eq(StringUtils.isNotEmpty(vehicleNo),
TAppStock::getVehicleId, vehicleNo)
.eq(TAppStock::getStockStatus, WmsStockStatusEnums.OK.getCode()))) {
if (!appLocationService.update( if (!appLocationService.update(
new LambdaUpdateWrapper<TAppLocation>().eq(TAppLocation::getLocationId, location.getLocationId()) new LambdaUpdateWrapper<TAppLocation>().eq(TAppLocation::getLocationId, location.getLocationId())
.set(TAppLocation::getIsOccupy, WmsLocationOccupyStatusEnums.EMPTY.getCode()) .set(TAppLocation::getIsOccupy, WmsLocationOccupyStatusEnums.EMPTY.getCode())
@ -297,6 +297,6 @@ public class MyWmsControllerServiceImpl implements IMyWmsControllerService {
} else { } else {
return "该载具已在库中,无法清除库位信息 / 库位表中无数据"; return "该载具已在库中,无法清除库位信息 / 库位表中无数据";
} }
} }
} }

View File

@ -4,7 +4,6 @@ import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.wms_main.constant.enums.wcs.WcsApiResponseCodeEnums; import com.wms_main.constant.enums.wcs.WcsApiResponseCodeEnums;
import com.wms_main.constant.enums.wcs.WcsStackerTaskStatusEnums; import com.wms_main.constant.enums.wcs.WcsStackerTaskStatusEnums;
import com.wms_main.constant.enums.wcs.WcsStackerTaskTypeEnums;
import com.wms_main.constant.enums.wms.WmsStackerTaskStatusEnums; import com.wms_main.constant.enums.wms.WmsStackerTaskStatusEnums;
import com.wms_main.dao.ITAppTaskService; import com.wms_main.dao.ITAppTaskService;
import com.wms_main.dao.ITAppWcsTaskService; import com.wms_main.dao.ITAppWcsTaskService;
@ -15,7 +14,6 @@ import com.wms_main.model.po.TAppTask;
import com.wms_main.model.po.TAppWcsTask; import com.wms_main.model.po.TAppWcsTask;
import com.wms_main.repository.utils.StringUtils; import com.wms_main.repository.utils.StringUtils;
import com.wms_main.service.api.IWcsApiService; import com.wms_main.service.api.IWcsApiService;
import com.wms_main.service.business.IAgvLockService;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.quartz.*; import org.quartz.*;
@ -44,11 +42,6 @@ public class WcsStackerTaskSender implements Job {
* Wcs接口服务 * Wcs接口服务
*/ */
private final IWcsApiService wcsApiService; private final IWcsApiService wcsApiService;
/**
* AGV锁定服务
*/
private final IAgvLockService agvLockService;
/** /**
* 运行定时任务 * 运行定时任务
* 向Wcs发送堆垛机任务 * 向Wcs发送堆垛机任务
@ -73,18 +66,6 @@ public class WcsStackerTaskSender implements Job {
waitSendWcsTaskList.sort((task1, task2) -> Integer.compare(task2.getTaskPriority(), task1.getTaskPriority())); waitSendWcsTaskList.sort((task1, task2) -> Integer.compare(task2.getTaskPriority(), task1.getTaskPriority()));
// 发送任务 // 发送任务
TAppWcsTask wcsTask = waitSendWcsTaskList.getFirst(); TAppWcsTask wcsTask = waitSendWcsTaskList.getFirst();
Boolean wmsAllow = false;
if (wcsTask.getWcsTaskType().equals(WcsStackerTaskTypeEnums.OUT.getCode())) {
wmsAllow = agvLockService.canFeedToOutboundPort(wcsTask.getDestination());
} else if (wcsTask.getWcsTaskType().equals(WcsStackerTaskTypeEnums.IN.getCode())) {
wmsAllow = agvLockService.canFeedToInboundPort(wcsTask.getOrigin());
}
if (wcsTask.getWcsTaskType().equals(WcsStackerTaskTypeEnums.OUT.getCode())
|| wcsTask.getWcsTaskType().equals(WcsStackerTaskTypeEnums.IN.getCode())) {
if (!wmsAllow) {
return;
}
}
// 生成请求 // 生成请求
WcsStackerTaskRequest request = new WcsStackerTaskRequest( WcsStackerTaskRequest request = new WcsStackerTaskRequest(
wcsTask.getWcsTaskId(), wcsTask.getWcsTaskId(),
@ -107,20 +88,6 @@ public class WcsStackerTaskSender implements Job {
new LambdaUpdateWrapper<TAppTask>() new LambdaUpdateWrapper<TAppTask>()
.set(TAppTask::getTaskStatus, WmsStackerTaskStatusEnums.SEND.getCode()) .set(TAppTask::getTaskStatus, WmsStackerTaskStatusEnums.SEND.getCode())
.eq(TAppTask::getWcsTaskId, wcsTask.getWcsTaskId())); .eq(TAppTask::getWcsTaskId, wcsTask.getWcsTaskId()));
if (wcsTask.getWcsTaskType().equals(WcsStackerTaskTypeEnums.OUT.getCode())) {
try {
agvLockService.lockOutboundPort("AGV", wcsTask.getDestination());
} catch (Exception e) {
log.error("任务发送成功后锁定{}口失败任务ID: {}", wcsTask.getDestination(), wcsTask.getWcsTaskId());
}
} else if (wcsTask.getWcsTaskType().equals(WcsStackerTaskTypeEnums.IN.getCode())) {
try {
agvLockService.lockInboundPort("AGV", wcsTask.getOrigin());
} catch (Exception e) {
log.error("任务发送成功后锁定{}口失败任务ID: {}", wcsTask.getOrigin(), wcsTask.getWcsTaskId());
}
}
} else { } else {
log.error("堆垛机任务发送失败,请求{},响应信息{}。", StringUtils.objectToString(request), log.error("堆垛机任务发送失败,请求{},响应信息{}。", StringUtils.objectToString(request),
StringUtils.objectToString(wcsResponse)); StringUtils.objectToString(wcsResponse));

View File

@ -5,13 +5,13 @@ spring:
datasource: datasource:
driver-class-name: com.mysql.cj.jdbc.Driver driver-class-name: com.mysql.cj.jdbc.Driver
# 本地 # 本地
# url: jdbc:mysql://localhost:3306/wms_mengyang_tp?characterEncoding=utf8&serverTimezone=Asia/Shanghai&allowMultiQueries=true&rewriteBatchedStatements=true
# username: root
# password: root
# 服务器
url: jdbc:mysql://localhost:3306/wms_mengyang_tp?characterEncoding=utf8&serverTimezone=Asia/Shanghai&allowMultiQueries=true&rewriteBatchedStatements=true url: jdbc:mysql://localhost:3306/wms_mengyang_tp?characterEncoding=utf8&serverTimezone=Asia/Shanghai&allowMultiQueries=true&rewriteBatchedStatements=true
username: user username: root
password: user password: root
# 服务器
# url: jdbc:mysql://localhost:3306/wms_mengyang_tp?characterEncoding=utf8&serverTimezone=Asia/Shanghai&allowMultiQueries=true&rewriteBatchedStatements=true
# username: user
# password: user
profiles: profiles:
active: online active: online