feat: 自动补空任务

This commit is contained in:
2026-08-13 16:47:46 +08:00
parent 6db59d422d
commit 5ada3c2a41
7 changed files with 239 additions and 8 deletions

View File

@@ -9,7 +9,8 @@ import lombok.Getter;
*/
@Getter
public enum PackageTaskTypeEnum {
SUB_ROLL_DOWN_AGV("010601", "子卷->待检AGV任务"),
SUB_ROLL_DOWN_AGV("010601", "子卷下线到待检AGV任务"),
SUB_ROLL_CALL_EMPTY_AGV("010602", "子卷下线补空架AGV任务"),
;
/**
* 字典键值

View File

@@ -46,17 +46,19 @@ public interface PackagePointMapper extends BaseMapperX<PackagePointDO> {
* 尝试锁定点位
*
* @param pointId 点位标识
* @param pointStatus 预期点位状态
* @return 更新行数
*/
int tryLockPoint(@Param("pointId") Long pointId);
int tryLockPoint(@Param("pointId") Long pointId, @Param("pointStatus") String pointStatus);
/**
* 释放点位锁
*
* @param pointId 点位标识
* @param pointStatus 预期点位状态
* @return 更新行数
*/
int unlockPoint(@Param("pointId") Long pointId);
int unlockPoint(@Param("pointId") Long pointId, @Param("pointStatus") String pointStatus);
default PageResult<PackagePointDO> selectPage(PackagePointPageReqVO reqVO) {
return selectPage(reqVO, new LambdaQueryWrapperX<PackagePointDO>()

View File

@@ -44,6 +44,14 @@ public class BoxAutoJob {
@XxlJob("autoSubRollDownCallEmptyJob")
@TenantJob
public void autoSubRollDownCallEmptyJob() {
log.info("子卷下线补充空架子任务创建开始.....");
XxlJobHelper.log("子卷下线补充空架子任务创建开始");
packageBoxBusinessService.autoSubRollDownCallEmpty();
String msg = "子卷下线补充空架子任务创建结束";
XxlJobHelper.log(msg);
XxlJobHelper.handleSuccess(msg);
log.info(msg);
}
}

View File

@@ -11,4 +11,9 @@ public interface PackageBoxBusinessService {
* 自动创建子卷下线送待检区任务
*/
void autoSendSubRollTask();
/**
* 自动创建子卷下线补充空架子任务
*/
void autoSubRollDownCallEmpty();
}

View File

@@ -33,6 +33,12 @@ public class PackageBoxBusinessServiceImpl implements PackageBoxBusinessService
/** 子卷下线任务回调处理器编码 */
private static final String SUB_ROLL_DOWN_HANDLE_CODE = "subRollDownAgvTask";
/** 子卷下线补充空架子业务类型 */
private static final String SUB_ROLL_CALL_EMPTY_BIZ_TYPE = "SUB_ROLL_CALL_EMPTY";
/** 子卷下线补充空架子任务回调处理器编码 */
private static final String SUB_ROLL_CALL_EMPTY_HANDLE_CODE = "subRollCallEmptyAgvTask";
/**
* ACS 搬运任务类型
*/
@@ -66,13 +72,13 @@ public class PackageBoxBusinessServiceImpl implements PackageBoxBusinessService
Iterator<PackagePointDO> destinationIterator = destinationPointList.iterator();
for (PackagePointDO sourcePoint : sourcePointList) {
if (packagePointMapper.tryLockPoint(sourcePoint.getPointId()) == 0) {
if (packagePointMapper.tryLockPoint(sourcePoint.getPointId(), sourcePoint.getPointStatus()) == 0) {
continue;
}
PackagePointDO destinationPoint = lockNextDestinationPoint(destinationIterator);
if (destinationPoint == null) {
packagePointMapper.unlockPoint(sourcePoint.getPointId());
packagePointMapper.unlockPoint(sourcePoint.getPointId(), sourcePoint.getPointStatus());
log.info("没有可用的待检区点位,结束本轮任务创建");
break;
}
@@ -83,6 +89,47 @@ public class PackageBoxBusinessServiceImpl implements PackageBoxBusinessService
}
}
/**
* 自动创建子卷下线补充空架子任务
*/
@Override
@Transactional(rollbackFor = Exception.class)
public void autoSubRollDownCallEmpty() {
List<PackagePointDO> offlineEmptyPointList = packagePointMapper.selectAvailablePointList(
BoxPointTypeEnum.OFFLINE_POINT.getCode(), BoxPointStatusEnum.EMPTY.getCode());
List<PackagePointDO> packingEmptyContainerPointList = packagePointMapper.selectAvailablePointList(
BoxPointTypeEnum.PACKING_POINT.getCode(), BoxPointStatusEnum.EMPTY_CONTAINER.getCode());
List<PackagePointDO> inspectionEmptyContainerPointList = packagePointMapper.selectAvailablePointList(
BoxPointTypeEnum.INSPECTION_PENDING_POINT.getCode(), BoxPointStatusEnum.EMPTY_CONTAINER.getCode());
List<PackagePointDO> inspectionEmptyPointList = packagePointMapper.selectAvailablePointList(
BoxPointTypeEnum.INSPECTION_PENDING_POINT.getCode(), BoxPointStatusEnum.EMPTY.getCode());
Iterator<PackagePointDO> packingSourceIterator = packingEmptyContainerPointList.iterator();
Iterator<PackagePointDO> inspectionSourceIterator = inspectionEmptyContainerPointList.iterator();
for (PackagePointDO offlineDestinationPoint : offlineEmptyPointList) {
if (packagePointMapper.tryLockPoint(
offlineDestinationPoint.getPointId(), offlineDestinationPoint.getPointStatus()) == 0) {
continue;
}
PackagePointDO sourcePoint = lockNextSourcePoint(packingSourceIterator);
if (sourcePoint == null) {
sourcePoint = lockNextSourcePoint(inspectionSourceIterator);
}
if (sourcePoint == null) {
packagePointMapper.unlockPoint(
offlineDestinationPoint.getPointId(), offlineDestinationPoint.getPointStatus());
break;
}
Long taskId = createCallEmptyTransportTask(sourcePoint, offlineDestinationPoint);
log.info("子卷下线补充空架子任务创建成功,任务标识={},起点编码={},目的点编码={}",
taskId, sourcePoint.getPointCode(), offlineDestinationPoint.getPointCode());
}
createPackingToInspectionTask(packingSourceIterator, inspectionEmptyPointList.iterator());
}
/**
* 创建子卷下线送待检区运输任务
*
@@ -110,6 +157,75 @@ public class PackageBoxBusinessServiceImpl implements PackageBoxBusinessService
return transportTaskApi.createTransportTask(task).getCheckedData();
}
/**
* 创建子卷下线补充空架子运输任务
*
* @param sourcePoint 起点
* @param destinationPoint 目的点
* @return 运输任务标识
*/
private Long createCallEmptyTransportTask(PackagePointDO sourcePoint, PackagePointDO destinationPoint) {
TransportTaskCreateReqDTO task = new TransportTaskCreateReqDTO();
task.setTaskName("子卷下线补充空架子任务");
task.setOwnerService(TaskOwnerServiceEnum.LMS.name());
task.setBizType(SUB_ROLL_CALL_EMPTY_BIZ_TYPE);
task.setBizId(sourcePoint.getVehicleCode());
task.setTaskType(PackageTaskTypeEnum.SUB_ROLL_CALL_EMPTY_AGV.getCode());
task.setHandleCode(SUB_ROLL_CALL_EMPTY_HANDLE_CODE);
task.setAcsTaskType(ACS_MOVE_TASK_TYPE);
task.setAgvSystemType(AGV_SYSTEM_TYPE);
task.setPointCode1(sourcePoint.getPointCode());
task.setPointCode2(destinationPoint.getPointCode());
task.setVehicleCode(sourcePoint.getVehicleCode());
task.setProductArea(sourcePoint.getProductArea());
task.setIsAutoIssue("1");
task.setIsCreateFinish(true);
return transportTaskApi.createTransportTask(task).getCheckedData();
}
/**
* 将剩余装箱点空架子转运到待检点空位
*
* @param sourceIterator 装箱点空架子候选迭代器
* @param destinationIterator 待检点空位候选迭代器
*/
private void createPackingToInspectionTask(Iterator<PackagePointDO> sourceIterator,
Iterator<PackagePointDO> destinationIterator) {
while (destinationIterator.hasNext()) {
PackagePointDO destinationPoint = destinationIterator.next();
if (packagePointMapper.tryLockPoint(
destinationPoint.getPointId(), destinationPoint.getPointStatus()) == 0) {
continue;
}
PackagePointDO sourcePoint = lockNextSourcePoint(sourceIterator);
if (sourcePoint == null) {
packagePointMapper.unlockPoint(destinationPoint.getPointId(), destinationPoint.getPointStatus());
break;
}
Long taskId = createCallEmptyTransportTask(sourcePoint, destinationPoint);
log.info("装箱点空架子送待检点任务创建成功,任务标识={},起点编码={},目的点编码={}",
taskId, sourcePoint.getPointCode(), destinationPoint.getPointCode());
}
}
/**
* 从候选点位中锁定下一个可用的空架子起点
*
* @param sourceIterator 空架子起点候选迭代器
* @return 成功锁定的起点,没有可用点位时返回 null
*/
private PackagePointDO lockNextSourcePoint(Iterator<PackagePointDO> sourceIterator) {
while (sourceIterator.hasNext()) {
PackagePointDO sourcePoint = sourceIterator.next();
if (packagePointMapper.tryLockPoint(sourcePoint.getPointId(), sourcePoint.getPointStatus()) > 0) {
return sourcePoint;
}
}
return null;
}
/**
* 从候选点位中锁定下一个可用的待检区点位
*
@@ -119,7 +235,8 @@ public class PackageBoxBusinessServiceImpl implements PackageBoxBusinessService
private PackagePointDO lockNextDestinationPoint(Iterator<PackagePointDO> destinationIterator) {
while (destinationIterator.hasNext()) {
PackagePointDO destinationPoint = destinationIterator.next();
if (packagePointMapper.tryLockPoint(destinationPoint.getPointId()) > 0) {
if (packagePointMapper.tryLockPoint(
destinationPoint.getPointId(), destinationPoint.getPointStatus()) > 0) {
return destinationPoint;
}
}

View File

@@ -0,0 +1,92 @@
package cn.code.nl.module.lms.tasks.box;
import cn.code.nl.framework.execute.core.AbstractTask;
import cn.code.nl.framework.execute.core.dto.TaskExecuteDTO;
import cn.code.nl.module.lms.dal.dataobject.packagepoint.PackagePointDO;
import cn.code.nl.module.lms.dal.mysql.packagepoint.PackagePointMapper;
import cn.code.nl.module.lms.enums.BoxPointStatusEnum;
import cn.code.nl.module.task.api.TransportTaskApi;
import cn.code.nl.module.task.dto.TaskInfoDTO;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import java.util.List;
/**
* 子卷下线补充空架子 AGV 任务
*
* @Author: liyongde
* @Date: 2026/8/13
*/
@Slf4j
@Component("subRollCallEmptyAgvTask")
public class SubRollCallEmptyAgvTask extends AbstractTask {
/** 运输任务接口 */
@Resource
private TransportTaskApi transportTaskApi;
/** 装箱点位 Mapper */
@Resource
private PackagePointMapper packagePointMapper;
/**
* 任务完成后将目的点更新为空载具
*
* @param taskExecuteDTO 任务执行信息
*/
@Override
public void doHandleFinish(TaskExecuteDTO taskExecuteDTO) {
TaskInfoDTO taskInfoDTO = transportTaskApi.getTaskById(taskExecuteDTO.getTaskId()).getCheckedData();
PackagePointDO endPoint = packagePointMapper.selectByPointCode(taskInfoDTO.getPointCode2(), false);
PackagePointDO updatePoint = new PackagePointDO();
updatePoint.setPointId(endPoint.getPointId());
updatePoint.setVehicleCode(taskInfoDTO.getVehicleCode());
updatePoint.setContainerName("");
updatePoint.setPointStatus(BoxPointStatusEnum.EMPTY_CONTAINER.getCode());
updatePoint.setLockStatus("0");
packagePointMapper.updateById(updatePoint);
log.info("任务{}执行完成,空架子已存入点位{}", taskExecuteDTO.getTaskId(), taskInfoDTO.getPointCode2());
}
/**
* 任务取消后解锁起点和目的点
*
* @param taskExecuteDTO 任务执行信息
*/
@Override
public void doHandleCancel(TaskExecuteDTO taskExecuteDTO) {
TaskInfoDTO taskInfoDTO = transportTaskApi.getTaskById(taskExecuteDTO.getTaskId()).getCheckedData();
PackagePointDO startPoint = packagePointMapper.selectByPointCode(taskInfoDTO.getPointCode1(), false);
PackagePointDO endPoint = packagePointMapper.selectByPointCode(taskInfoDTO.getPointCode2(), false);
PackagePointDO updateStartPoint = new PackagePointDO();
updateStartPoint.setPointId(startPoint.getPointId());
updateStartPoint.setLockStatus("0");
PackagePointDO updateEndPoint = new PackagePointDO();
updateEndPoint.setPointId(endPoint.getPointId());
updateEndPoint.setLockStatus("0");
packagePointMapper.updateBatch(List.of(updateStartPoint, updateEndPoint));
log.info("任务{}已取消,起点{}和目的点{}已解锁", taskExecuteDTO.getTaskId(),
taskInfoDTO.getPointCode1(), taskInfoDTO.getPointCode2());
}
/**
* 取货完成后将起点更新为空位
*
* @param taskExecuteDTO 任务执行信息
*/
@Override
public void doHandlePicked(TaskExecuteDTO taskExecuteDTO) {
TaskInfoDTO taskInfoDTO = transportTaskApi.getTaskById(taskExecuteDTO.getTaskId()).getCheckedData();
PackagePointDO startPoint = packagePointMapper.selectByPointCode(taskInfoDTO.getPointCode1(), false);
PackagePointDO updatePoint = new PackagePointDO();
updatePoint.setPointId(startPoint.getPointId());
updatePoint.setLockStatus("0");
updatePoint.setPointStatus(BoxPointStatusEnum.EMPTY.getCode());
updatePoint.setVehicleCode("");
updatePoint.setContainerName("");
packagePointMapper.updateById(updatePoint);
log.info("任务{}执行取货完成,点位{}已释放", taskExecuteDTO.getTaskId(), taskInfoDTO.getPointCode1());
}
}

View File

@@ -16,16 +16,22 @@
<update id="tryLockPoint">
UPDATE lms_package_point
SET lock_status = '1'
SET lock_status = '1',
updater = '0',
update_time = CURRENT_TIMESTAMP
WHERE point_id = #{pointId}
AND point_status = #{pointStatus}
AND lock_status = '0'
AND deleted = b'0'
</update>
<update id="unlockPoint">
UPDATE lms_package_point
SET lock_status = '0'
SET lock_status = '0',
updater = '0',
update_time = CURRENT_TIMESTAMP
WHERE point_id = #{pointId}
AND point_status = #{pointStatus}
AND lock_status = '1'
AND deleted = b'0'
</update>