1.物料表分页查询

2.库位状态表明错误
liweidong
绫Umbrella 1 month ago
parent 67e3ebe4fb
commit ea83eb9eeb
  1. 23
      blade-ops/blade-job/src/main/java/org/springblade/job/processor/logistics/OrderBoxRefinement.java
  2. 4
      blade-service-api/blade-desk-api/src/main/java/org/springblade/desk/logistics/pojo/dto/AGVCallBackDto.java
  3. 5
      blade-service-api/blade-desk-api/src/main/java/org/springblade/desk/logistics/pojo/dto/BoxBindingDto.java
  4. 57
      blade-service-api/blade-desk-api/src/main/java/org/springblade/desk/logistics/pojo/dto/TaskDto.java
  5. 2
      blade-service-api/blade-desk-api/src/main/java/org/springblade/desk/logistics/pojo/entity/TaskExecuteRecord.java
  6. 25
      blade-service-api/blade-desk-api/src/main/java/org/springblade/desk/logistics/pojo/vo/TaskVO.java
  7. 5
      blade-service/blade-desk/src/main/java/org/springblade/desk/logistics/controller/AGVDockingController.java
  8. 36
      blade-service/blade-desk/src/main/java/org/springblade/desk/logistics/controller/OrderBoxController.java
  9. 16
      blade-service/blade-desk/src/main/java/org/springblade/desk/logistics/mapper/TaskMapper.java
  10. 31
      blade-service/blade-desk/src/main/java/org/springblade/desk/logistics/mapper/TaskMapper.xml
  11. 4
      blade-service/blade-desk/src/main/java/org/springblade/desk/logistics/service/IOrderBoxService.java
  12. 6
      blade-service/blade-desk/src/main/java/org/springblade/desk/logistics/service/ITaskExecuteRecordService.java
  13. 5
      blade-service/blade-desk/src/main/java/org/springblade/desk/logistics/service/ITaskService.java
  14. 9
      blade-service/blade-desk/src/main/java/org/springblade/desk/logistics/service/impl/IOrderBoxServiceImpl.java
  15. 191
      blade-service/blade-desk/src/main/java/org/springblade/desk/logistics/service/impl/StorageMonitoringServiceImpl.java
  16. 113
      blade-service/blade-desk/src/main/java/org/springblade/desk/logistics/service/impl/TaskExecuteRecordServiceImpl.java
  17. 10
      blade-service/blade-desk/src/main/java/org/springblade/desk/logistics/service/impl/TaskServiceImpl.java

@ -0,0 +1,23 @@
package org.springblade.job.processor.logistics;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import tech.powerjob.worker.core.processor.ProcessResult;
import tech.powerjob.worker.core.processor.TaskContext;
import tech.powerjob.worker.core.processor.sdk.BasicProcessor;
/**
* 物流订单绑定模块
*/
@Component
@Data
@Slf4j
public class OrderBoxRefinement implements BasicProcessor {
@Override
public ProcessResult process(TaskContext taskContext) throws Exception {
System.out.println("hello world");
log.info("hello world");
return new ProcessResult(true);
}
}

@ -1,11 +1,11 @@
package org.springblade.desk.logistics.pojo.entity;
package org.springblade.desk.logistics.pojo.dto;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
@Data
@Schema(description = "箱绑定接收")
public class AGVCallBack {
public class AGVCallBackDto {
/**
* 请求编号每个请求都要一个唯一
* 编号 同一个请求重复提交 使

@ -1,14 +1,13 @@
package org.springblade.desk.logistics.pojo.entity;
package org.springblade.desk.logistics.pojo.dto;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.util.ArrayList;
@Data
@Schema(description = "箱绑定接收表")
public class BoxBinding {
public class BoxBindingDto {
private String boxBarcode;
private ArrayList<Long> orderIdList;
private Long wcId;

@ -0,0 +1,57 @@
package org.springblade.desk.logistics.pojo.dto;
import com.baomidou.mybatisplus.annotation.TableName;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.springblade.core.mp.base.BaseEntity;
import java.io.Serial;
import java.math.BigDecimal;
import java.util.Date;
/**
* 物流任务实体类
*
* @author: liweidong
* @create: 2026-03-03
*/
@Data
@Schema(description = "物流任务对象")
public class TaskDto extends BaseEntity {
/**
* 箱条码
*/
@Schema(description = "箱条码")
private String boxBarcode;
/**
* 站点ID
*/
@Schema(description = "站点ID")
private Long stationId;
/**
* 作业中心ID
*/
@Schema(description = "作业中心ID")
private Long wcId;
/**
* 当前状态 0:退回(超重) 1:站点 2:库位 3:等待 4:回库 5:结束
*/
@Schema(description = "当前状态 0:退回(超重) 1:站点 2:库位 3:等待 4:回库 5:结束")
private Integer taskStatus;
/**
* 开始时间
*/
@Schema(description = "开始时间")
private Date startTime;
/**
* 结束时间
*/
@Schema(description = "结束时间")
private Date endTime;
}

@ -35,7 +35,7 @@ public class TaskExecuteRecord extends BaseEntity {
public static final String STATUS_START = "start";
/**
* 状态常量走出储位
* 状态常量结束
*/
public static final String STATUS_END = "end";

@ -0,0 +1,25 @@
package org.springblade.desk.logistics.pojo.vo;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.springblade.desk.device.pojo.entity.EquipmentEntity;
import org.springblade.desk.logistics.pojo.entity.Task;
import java.io.Serial;
@Data
@EqualsAndHashCode(callSuper = true)
public class TaskVO extends Task {
@Serial
private static final long serialVersionUID = 1L;
/**
* 主键ID
*/
@JsonSerialize(using = ToStringSerializer.class)
private Long id;
/**
* 状态名称
*/
// String statusName;
}

@ -5,7 +5,8 @@ import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.AllArgsConstructor;
import org.springblade.core.tool.api.R;
import org.springblade.desk.logistics.pojo.entity.AGVCallBack;
import org.springblade.desk.logistics.pojo.dto.AGVCallBackDto;
import org.springblade.desk.logistics.service.IOrderBoxService;
import org.springblade.desk.logistics.service.ITaskExecuteRecordService;
import org.springframework.web.bind.annotation.PostMapping;
@ -34,7 +35,7 @@ public class AGVDockingController {
summary = "agv小车回调接口",
description = "AGV小车回调接口"
)
public R agvCallback(@RequestBody AGVCallBack agvCallBack ){
public R agvCallback(@RequestBody AGVCallBackDto agvCallBack ){
// 1.参数合法性校验
if (agvCallBack == null || agvCallBack.getTaskCode().trim().isEmpty()) {
return R.fail("任务单号不能为空");

@ -1,22 +1,31 @@
package org.springblade.desk.logistics.controller;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.Parameters;
import io.swagger.v3.oas.annotations.enums.ParameterIn;
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.AllArgsConstructor;
import org.springblade.core.boot.ctrl.BladeController;
import org.springblade.core.mp.support.Condition;
import org.springblade.core.mp.support.Query;
import org.springblade.core.tool.api.R;
import org.springblade.desk.dashboard.pojo.entity.BsWorkCenterEntity;
import org.springblade.desk.dashboard.service.IBsWorkCenterService;
import org.springblade.desk.dashboard.wrapper.BsWorkCenterWrapper;
import org.springblade.desk.logistics.pojo.entity.BoxBinding;
import org.springblade.desk.device.pojo.entity.EquipmentEntity;
import org.springblade.desk.device.pojo.vo.EquipmentVO;
import org.springblade.desk.logistics.pojo.dto.BoxBindingDto;
import org.springblade.desk.logistics.pojo.dto.TaskDto;
import org.springblade.desk.logistics.pojo.vo.TaskVO;
import org.springblade.desk.logistics.service.IOrderBoxService;
import org.springblade.desk.logistics.service.ITaskService;
import org.springframework.web.bind.annotation.*;
import java.math.BigDecimal;
import java.util.List;
/**
* 订单箱子 控制器
@ -31,6 +40,7 @@ import java.util.List;
public class OrderBoxController extends BladeController {
private final IOrderBoxService iOrderBoxService;
private final IBsWorkCenterService bsWorkCenterService;
private final ITaskService taskService;
@PostMapping("/getWeighing")
@ -70,7 +80,7 @@ public class OrderBoxController extends BladeController {
summary = "绑定箱条码和订单",
description = "绑定箱条码和订单信息内容"
)
public R boxBinding(@RequestBody BoxBinding boxBinding){
public R boxBinding(@RequestBody BoxBindingDto boxBinding){
// 1.参数合法性校验
if (boxBinding == null || boxBinding.getBoxBarcode().trim().isEmpty()) {
return R.fail("箱条码不能为空");
@ -81,6 +91,24 @@ public class OrderBoxController extends BladeController {
return iOrderBoxService.boxBinding(boxBinding);
}
/**
* 任务表 自定义分页
*/
@GetMapping("/page")
@ApiOperationSupport(order = 4)
@Operation(summary = "分页", description = "")
@Parameters({
@Parameter(name = "boxBarcode", description = "箱条码", in = ParameterIn.QUERY, schema = @Schema(type = "String")),
@Parameter(name = "stationId", description = "站点ID", in = ParameterIn.QUERY, schema = @Schema(type = "Long")),
@Parameter(name = "wcId", description = "作业中心ID", in = ParameterIn.QUERY, schema = @Schema(type = "Long")),
@Parameter(name = "taskStatus", description = "当前状态 0:退回(超重) 1:站点 2:库位 3:等待 4:回库 5:结束", in = ParameterIn.QUERY, schema = @Schema(type = "Integer")),
@Parameter(name = "startTime", description = "开始时间", in = ParameterIn.QUERY, schema = @Schema(type = "Date")),
@Parameter(name = "endTime", description = "结束时间", in = ParameterIn.QUERY, schema = @Schema(type = "Date"))
})
public R<IPage<TaskVO>> page(@Parameter(hidden = true) TaskDto taskDto, Query query) {
IPage<TaskVO> pages = taskService.selectPage(Condition.getPage(query), taskDto);
return R.data(pages);
}
}

@ -1,10 +1,26 @@
package org.springblade.desk.logistics.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import org.apache.ibatis.annotations.Param;
import org.springblade.desk.device.pojo.entity.EquipmentEntity;
import org.springblade.desk.device.pojo.vo.EquipmentVO;
import org.springblade.desk.logistics.pojo.dto.TaskDto;
import org.springblade.desk.logistics.pojo.entity.Task;
import org.springblade.desk.logistics.pojo.entity.WeighData;
import org.springblade.desk.logistics.pojo.vo.TaskVO;
import java.util.List;
public interface TaskMapper extends BaseMapper<Task> {
Task selectByBoxBarcode(@Param("boxBarcode") String boxBarcode);
/**
* 自定义分页
*
* @param page 分页参数
* @param taskDto 查询参数
* @return List<EquipmentVO>
*/
List<TaskVO> selectEquipmentPage(IPage page, TaskDto taskDto);
}

@ -12,4 +12,35 @@
AND BOX_BARCODE = #{boxBarcode}
AND TASK_STATUS NOT IN (2, 9);
</select>
<select id="selectEquipmentPage" resultType="org.springblade.desk.logistics.pojo.vo.TaskVO">
SELECT *
FROM LM_TASK l
WHERE IS_DELETED = 0
<!-- 修复原代码拼写错误:boxBarcodede → boxBarcode -->
<if test="taskDto.boxBarcode != null and taskDto.boxBarcode != ''">
AND l.BOX_BARCODE LIKE CONCAT('%', #{taskDto.boxBarcode}, '%')
</if>
<!-- wcId 判断 -->
<if test="taskDto.wcId != null and taskDto.wcId != ''">
AND l.WC_ID = #{taskDto.wcId}
</if>
<!-- 站点 判断 -->
<if test="taskDto.stationId != null and taskDto.stationId != ''">
AND l.STATION_ID = #{taskDto.stationId}
</if>
<!-- 状态判断 -->
<if test="taskDto.taskStatus != null and taskDto.taskStatus != ''">
AND l.TASK_STATUS = #{taskDto.taskStatus}
</if>
<!-- 新增:开始时间判断(CREATE_TIME >= 开始时间) -->
<if test="taskDto.startTime != null">
AND l.CREATE_TIME &gt;= #{taskDto.startTime}
</if>
<!-- 新增:结束时间判断(CREATE_TIME <= 结束时间) -->
<if test="taskDto.endTime != null">
AND l.CREATE_TIME &lt;= #{taskDto.endTime}
</if>
ORDER BY l.CREATE_TIME DESC
</select>
</mapper>

@ -1,7 +1,7 @@
package org.springblade.desk.logistics.service;
import org.springblade.core.tool.api.R;
import org.springblade.desk.logistics.pojo.entity.BoxBinding;
import org.springblade.desk.logistics.pojo.dto.BoxBindingDto;
import java.math.BigDecimal;
@ -35,7 +35,7 @@ public interface IOrderBoxService {
* - 成功R.success()携带绑定成功的提示或绑定记录数
* - 失败R.fail()携带失败原因如箱条码不存在订单已绑定唯一约束冲突等
*/
R boxBinding(BoxBinding boxBinding);
R boxBinding(BoxBindingDto boxBinding);
/**
* 箱条码与订单解绑

@ -27,8 +27,8 @@ package org.springblade.desk.logistics.service;
import org.springblade.core.mp.base.BaseService;
import org.springblade.core.tool.api.R;
import org.springblade.desk.logistics.pojo.entity.AGVCallBack;
import org.springblade.desk.logistics.pojo.entity.OrderBind;
import org.springblade.desk.logistics.pojo.dto.AGVCallBackDto;
import org.springblade.desk.logistics.pojo.entity.TaskExecuteRecord;
/**
@ -39,5 +39,5 @@ import org.springblade.desk.logistics.pojo.entity.TaskExecuteRecord;
*/
public interface ITaskExecuteRecordService extends BaseService<TaskExecuteRecord> {
R agvCallback(AGVCallBack agvCallBack);
R agvCallback(AGVCallBackDto agvCallBack);
}

@ -25,8 +25,11 @@
*/
package org.springblade.desk.logistics.service;
import com.baomidou.mybatisplus.core.metadata.IPage;
import org.springblade.core.mp.base.BaseService;
import org.springblade.desk.logistics.pojo.dto.TaskDto;
import org.springblade.desk.logistics.pojo.entity.Task;
import org.springblade.desk.logistics.pojo.vo.TaskVO;
import java.math.BigDecimal;
@ -52,4 +55,6 @@ public interface ITaskService extends BaseService<Task> {
* @return
*/
Task getBoxBarcode(String boxBarcode);
IPage<TaskVO> selectPage(IPage<TaskVO> page, TaskDto taskDto);
}

@ -5,11 +5,11 @@ import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import lombok.extern.slf4j.Slf4j;
import org.springblade.core.secure.utils.AuthUtil;
import org.springblade.core.tool.api.R;
import org.springblade.desk.logistics.pojo.dto.BoxBindingDto;
import org.springblade.desk.logistics.pojo.entity.*;
import org.springblade.desk.logistics.service.*;
import org.springblade.desk.order.pojo.entity.YieldOrder;
import org.springblade.desk.order.service.IYieldOrderService;
import org.springblade.system.pojo.entity.AuthClient;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
@ -19,7 +19,6 @@ import java.util.stream.Collectors;
import static org.springblade.desk.logistics.pojo.entity.OrderBind.STATUS_UNBINDED;
import static org.springblade.desk.logistics.pojo.entity.Station.STATUS_OCCUPIED;
import static org.springblade.desk.logistics.pojo.entity.Task.STATUS_FINISHED;
/**
* 订单箱业务实现类
@ -120,7 +119,7 @@ public class IOrderBoxServiceImpl implements IOrderBoxService {
* - 失败R.fail()携带具体失败原因如参数为空订单已绑定重量超限等
*/
@Override
public R boxBinding(BoxBinding boxBinding) {
public R boxBinding(BoxBindingDto boxBinding) {
log.info("接收到箱绑定实际参数:{}", boxBinding);
// 1. 入参非空校验(基础防护)
@ -309,12 +308,12 @@ public class IOrderBoxServiceImpl implements IOrderBoxService {
}
// 2. 站点无可用则查询可用库位(状态为占用的库位)
List<Location> locationList = iLocationService.list(new LambdaQueryWrapper<Location>().eq(Location::getLocationStatus, Location.STATUS_OCCUPIED));
List<Location> locationList = iLocationService.list(new LambdaQueryWrapper<Location>().eq(Location::getLocationStatus, Location.STATUS_FREE));
if (!CollectionUtils.isEmpty(locationList)) {
task.setLocationId(locationList.get(0).getId()); // 分配第一个可用库位
// 更新库位状态为空闲(锁定库位)
Location location = locationList.get(0);
location.setLocationStatus(Location.STATUS_FREE);
location.setLocationStatus(Location.STATUS_OCCUPIED);
iLocationService.updateById(location);
return R.data(task);
}

@ -1,50 +1,185 @@
package org.springblade.desk.logistics.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import lombok.extern.slf4j.Slf4j;
import org.springblade.desk.logistics.pojo.entity.Location;
import org.springblade.desk.logistics.pojo.entity.Station;
import org.springblade.desk.logistics.pojo.entity.Task;
import org.springblade.desk.logistics.service.ILocationService;
import org.springblade.desk.logistics.service.IStationService;
import org.springblade.desk.logistics.service.IStorageMonitoringService;
import org.springblade.desk.logistics.service.ITaskService;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;
import java.util.HashSet;
import java.util.Set;
import java.util.List;
@Service
/**
* 仓储监控服务实现类
* <p>
* 核心业务
* 1. 定时每5秒扫描系统中所有空闲状态的站点
* 2. 为每个空闲站点匹配最早创建的待库位任务
* 3. 更新任务关联库位为空闲状态并绑定站点与任务关系
* 4. 触发AGV小车移动指令待实现
* <p>
* 设计思路
* - 采用定时任务自动巡检减少人工干预
* - 按任务创建时间升序匹配保证任务执行的公平性
* - 增加多层空值防护和状态校验避免无效数据库操作
*
* @author 可补充作者信息
* @date 2026-03-05
* @version 1.0
*/
@Service // Spring业务层注解,将类注册为Spring Bean
@Slf4j // Lombok日志注解,自动生成log对象,无需手动创建Logger
public class StorageMonitoringServiceImpl implements IStorageMonitoringService {
private static final Set<Integer> RUNNING_STATUSES = new HashSet<>();
static {
// 初始化运行中任务状态
RUNNING_STATUSES.add(Task.STATUS_START); // 任务启动
RUNNING_STATUSES.add(Task.STATUS_CONVEYOR_START); // 输送机启动
RUNNING_STATUSES.add(Task.STATUS_CONVEYOR_END); // 输送机结束
RUNNING_STATUSES.add(Task.STATUS_STATION); // 站点状态
RUNNING_STATUSES.add(Task.STATUS_LOCATION); // 库位状态
RUNNING_STATUSES.add(Task.STATUS_WAITING); // 等待状态
RUNNING_STATUSES.add(Task.STATUS_STATION_RECEIVE);// 站点接收
RUNNING_STATUSES.add(Task.STATUS_BACK_TO_STORAGE);// 返库状态
}
/**
* 任务服务处理箱绑定任务的创建状态更新删除等
* 任务业务服务提供任务的CRUD状态查询条件筛选等操作
*/
private final ITaskService iTaskService;
private final ITaskService taskService;
/**
* 站点服务处理站点状态占用/空闲管理
* 站点业务服务提供站点状态管理站点信息查询等操作
*/
private final IStationService iStationService;
private final IStationService stationService;
/**
* 库位服务处理库位状态占用/空闲管理
* 库位业务服务提供库位状态更新库位信息查询等操作
*/
private final ILocationService iLocationService;
public StorageMonitoringServiceImpl(ITaskService iTaskService, IStationService iStationService, ILocationService iLocationService) {
this.iTaskService = iTaskService;
this.iStationService = iStationService;
this.iLocationService = iLocationService;
private final ILocationService locationService;
/**
* 构造器注入依赖Spring官方推荐方式
* <p>
* 优势
* 1. 强制依赖注入避免NPE空指针异常
* 2. 便于单元测试时模拟依赖
* 3. 符合依赖倒置原则降低耦合
*
* @param taskService 任务服务BeanSpring自动注入
* @param stationService 站点服务BeanSpring自动注入
* @param locationService 库位服务BeanSpring自动注入
*/
public StorageMonitoringServiceImpl(ITaskService taskService, IStationService stationService, ILocationService locationService) {
this.taskService = taskService;
this.stationService = stationService;
this.locationService = locationService;
}
@Override
/**
* 仓储空闲站点监控核心方法定时执行
* <p>
* 执行频率每5秒执行一次
* 核心流程
* 1. 拉取全量空闲状态的站点列表
* 2. 遍历每个空闲站点匹配对应工位的待库位任务
* 3. 对首个任务关联的库位执行置为空闲操作
* 4. 绑定任务与站点关系更新站点预占用状态
* 5. 触发AGV小车移动指令待实现
* <p>
* 异常防护
* - 空集合直接返回避免循环空指针
* - 库位ID/任务/库位信息空值校验跳过异常数据
* - 状态未变化时跳过更新减少数据库IO
*/
@Scheduled(cron = "*/5 * * * * ?") // Spring定时任务注解,cron表达式控制执行频率
@Override // 实现IStorageMonitoringService接口的抽象方法
public void monitoringStation() {
// ========== 步骤1:查询所有空闲状态的站点 ==========
List<Station> stationList = stationService.list(
new LambdaQueryWrapper<Station>()
.eq(Station::getStationStatus, Station.STATUS_FREE) // 筛选条件:站点状态为空闲
);
// 日志打印空闲站点数量,便于监控和问题排查
log.info("【仓储监控】定时任务执行 - 查询到空闲站点数量:{}", stationList == null ? 0 : stationList.size());
// 空值防护:无空闲站点时直接返回,避免后续无效操作
if (stationList == null || stationList.isEmpty()) {
log.warn("【仓储监控】定时任务执行 - 未查询到空闲站点,任务提前结束");
return;
}
// ========== 步骤2:遍历空闲站点处理关联任务 ==========
int processedCount = 0; // 统计成功处理的站点数量
for (Station station : stationList) {
// 打印当前处理的站点信息,便于定位单站点异常
log.info("【仓储监控】开始处理站点 - 站点ID:{},工位ID:{}", station.getId(), station.getWcId());
try {
// ========== 步骤2.1:查询对应工位的待库位任务(按创建时间升序) ==========
List<Task> taskList = taskService.list(
new LambdaQueryWrapper<Task>()
.eq(Task::getTaskStatus, Task.STATUS_LOCATION) // 任务状态:待库位
.eq(Task::getWcId, station.getWcId()) // 匹配当前站点的工位ID
.orderByAsc(Task::getCreateTime) // 按创建时间升序,优先处理最早创建的任务
);
// 无待处理任务时跳过当前站点
if (taskList == null || taskList.isEmpty()) {
log.info("【仓储监控】站点ID:{} - 未查询到待库位任务,跳过处理", station.getId());
continue;
}
// ========== 步骤2.2:获取首个任务并校验关联库位ID ==========
Task firstTask = taskList.get(0); // 取最早创建的待库位任务
Long locationId = firstTask.getLocationId(); // 获取任务关联的库位ID
log.info("【仓储监控】站点ID:{} - 匹配到首个待库位任务,任务ID:{},关联库位ID:{}",
station.getId(), firstTask.getId(), locationId);
// 空值防护:库位ID为空时跳过,避免后续查询异常
if (locationId == null) {
log.error("【仓储监控】任务ID:{} - 关联库位ID为空,跳过当前站点处理", firstTask.getId());
continue;
}
// ========== 步骤2.3:查询库位信息并更新状态为空闲 ==========
Location location = locationService.getById(locationId); // 根据库位ID查询库位信息
// 库位不存在时跳过
if (location == null) {
log.error("【仓储监控】库位ID:{} - 库位信息不存在,跳过当前站点处理", locationId);
continue;
}
// 状态校验:库位已为空闲时跳过更新,减少数据库操作
if (Location.STATUS_FREE.equals(location.getLocationStatus())) {
log.info("【仓储监控】库位ID:{} - 已为空闲状态,无需更新", locationId);
} else {
// 更新库位状态为空闲
location.setLocationStatus(Location.STATUS_FREE);
boolean updateResult = locationService.updateById(location);
if (updateResult) {
log.info("【仓储监控】库位ID:{} - 状态更新为空闲成功", locationId);
} else {
log.error("【仓储监控】库位ID:{} - 状态更新为空闲失败,跳过后续操作", locationId);
continue; // 更新失败时不触发AGV指令
}
}
// ========== 步骤2.4:绑定任务与站点关系,更新站点预占用状态 ==========
firstTask.setStationId(station.getId()); // 任务绑定当前站点ID
taskService.updateById(firstTask); // 保存任务关联关系
station.setStationStatus(Station.PRE_STATUS_OCCUPIED); // 站点置为预占用状态
stationService.updateById(station); // 保存站点状态
// ========== 步骤2.5:触发AGV小车移动指令(待实现) ==========
log.info("【仓储监控】站点ID:{} - 准备调用AGV接口,任务ID:{},库位ID:{}",
station.getId(), firstTask.getId(), locationId);
// todo: 调用AGV接口传递任务ID和站点ID,触发小车移动
// agvService.dispatchAgv(firstTask.getId(), station.getId());
processedCount++; // 成功处理计数+1
} catch (Exception e) {
// 单个站点处理异常不影响其他站点,记录异常日志便于排查
log.error("【仓储监控】站点ID:{} - 处理过程中发生异常,跳过当前站点", station.getId(), e);
continue;
}
}
// ========== 任务结束:打印处理结果 ==========
log.info("【仓储监控】定时任务执行完成 - 总计扫描空闲站点:{},成功处理:{}", stationList.size(), processedCount);
}
}
}

@ -1,47 +1,26 @@
/**
* BladeX Commercial License Agreement
* Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
* <p>
* Use of this software is governed by the Commercial License Agreement
* obtained after purchasing a license from BladeX.
* <p>
* 1. This software is for development use only under a valid license
* from BladeX.
* <p>
* 2. Redistribution of this software's source code to any third party
* without a commercial license is strictly prohibited.
* <p>
* 3. Licensees may copyright their own code but cannot use segments
* from this software for such purposes. Copyright of this software
* remains with BladeX.
* <p>
* Using this software signifies agreement to this License, and the software
* must not be used for illegal purposes.
* <p>
* THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
* not liable for any claims arising from secondary or illegal development.
* <p>
* Author: Chill Zhuang (bladejava@qq.com)
*/
package org.springblade.desk.logistics.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import lombok.extern.slf4j.Slf4j;
import org.springblade.core.mp.base.BaseServiceImpl;
import org.springblade.core.tool.api.R;
import org.springblade.desk.logistics.mapper.OrderBindMapper;
import org.springblade.desk.logistics.mapper.TaskExecuteRecordMapper;
import org.springblade.desk.logistics.pojo.entity.AGVCallBack;
import org.springblade.desk.logistics.pojo.entity.OrderBind;
import org.springblade.desk.logistics.pojo.dto.AGVCallBackDto;
import org.springblade.desk.logistics.pojo.entity.TaskExecuteRecord;
import org.springblade.desk.logistics.service.IOrderBindService;
import org.springblade.desk.logistics.service.ITaskExecuteRecordService;
import org.springframework.stereotype.Service;
import java.util.List;
/**
* 物流小车对接实体类 服务实现类
* 物流AGV小车任务执行记录服务实现类
* <p>
* 核心功能
* 1. 处理AGV小车执行任务后的回调通知
* 2. 更新任务执行记录的状态起始/结束位置等关键信息
* 3. 任务完成时触发后续的业务接口调用东哥接口
*
* @author BladeX
* @since 2025-11-12
@ -50,23 +29,83 @@ import java.util.List;
@Slf4j
public class TaskExecuteRecordServiceImpl extends BaseServiceImpl<TaskExecuteRecordMapper, TaskExecuteRecord> implements ITaskExecuteRecordService {
/**
* AGV小车任务状态回调接口
* <p>
* 处理逻辑
* 1. 接收AGV小车的回调参数记录日志并校验任务单号是否存在
* 2. 清理回调方法名的空格更新任务执行记录的方法字段
* 3. 根据不同的任务状态启动/出仓/结束更新对应的位置信息
* 4. 保存更新后的任务记录失败则返回错误结果
* 5. 任务结束时触发东哥接口调用待实现
*
* @param agvCallBack AGV小车回调参数实体包含任务单号执行方法当前位置等信息
* @return R<?> 统一返回结果
* - 成功R.success()
* - 失败R.fail(错误信息)
*/
@Override
public R agvCallback(AGVCallBack agvCallBack) {
log.info("agv小车接口调用参数入参:{}",agvCallBack);
List<TaskExecuteRecord> list = list(new LambdaQueryWrapper<TaskExecuteRecord>().eq(TaskExecuteRecord::getId, agvCallBack.getTaskCode()).orderByDesc(TaskExecuteRecord::getCreateTime));
if (list==null||list.size()==0) {
public R agvCallback(AGVCallBackDto agvCallBack) {
// 记录AGV回调入参,便于问题排查
log.info("agv小车接口调用参数入参:{}", agvCallBack);
// 1. 根据任务单号查询最新的任务执行记录(按创建时间降序,取第一条)
List<TaskExecuteRecord> list = list(
new LambdaQueryWrapper<TaskExecuteRecord>()
.eq(TaskExecuteRecord::getId, agvCallBack.getTaskCode())
.orderByDesc(TaskExecuteRecord::getCreateTime)
);
// 校验:未查询到任务记录,返回失败
if (list == null || list.isEmpty()) {
log.warn("AGV回调失败:未查询到任务单号为{}的执行记录", agvCallBack.getTaskCode());
return R.fail("未查询到该任务单号");
}
// 取最新的任务执行记录
TaskExecuteRecord taskExecuteRecord = list.get(0);
// 2. 清理方法名中的空格(避免因空格导致状态判断错误)
String method = agvCallBack.getMethod().replaceAll(" ", "");
taskExecuteRecord.setMethod(method);
if (!updateById(taskExecuteRecord)) {
// 3. 根据不同的任务状态更新对应的位置信息
switch (method) {
// 任务启动/出仓状态:更新起始位置
case TaskExecuteRecord.STATUS_START:
case TaskExecuteRecord.STATUS_OUTBIN:
taskExecuteRecord.setStartPos(agvCallBack.getCurrentPositionCode());
log.info("任务单号{}:更新起始位置为{},状态为{}",
agvCallBack.getTaskCode(), agvCallBack.getCurrentPositionCode(), method);
break;
// 任务结束状态:更新结束位置
case TaskExecuteRecord.STATUS_END:
taskExecuteRecord.setEndPos(agvCallBack.getCurrentPositionCode());
log.info("任务单号{}:更新结束位置为{},状态为{}",
agvCallBack.getTaskCode(), agvCallBack.getCurrentPositionCode(), method);
break;
// 其他状态:暂不处理位置信息
default:
log.info("任务单号{}:状态{}无需更新位置信息", agvCallBack.getTaskCode(), method);
break;
}
// 4. 保存更新后的任务记录
boolean updateResult = updateById(taskExecuteRecord);
if (!updateResult) {
log.error("AGV回调失败:任务单号{}的执行记录更新保存失败", agvCallBack.getTaskCode());
return R.fail("保存该任务单号失败");
}
// 5. 任务结束状态:触发后续的东哥接口调用(待实现)
if (method.equals(TaskExecuteRecord.STATUS_END)) {
log.info("任务单号{}已完成,准备调用东哥接口", agvCallBack.getTaskCode());
//todo: 调用东哥接口
// eastBrotherService.notifyTaskComplete(agvCallBack.getTaskCode());
}
// 回调处理成功
log.info("AGV回调成功:任务单号{}的执行记录已更新,状态为{}", agvCallBack.getTaskCode(), method);
return R.success();
}
}
}

@ -25,16 +25,20 @@
*/
package org.springblade.desk.logistics.service.impl;
import com.baomidou.mybatisplus.core.metadata.IPage;
import lombok.extern.slf4j.Slf4j;
import org.checkerframework.checker.units.qual.A;
import org.springblade.core.mp.base.BaseServiceImpl;
import org.springblade.desk.logistics.mapper.TaskMapper;
import org.springblade.desk.logistics.pojo.dto.TaskDto;
import org.springblade.desk.logistics.pojo.entity.Task;
import org.springblade.desk.logistics.pojo.vo.TaskVO;
import org.springblade.desk.logistics.service.ITaskService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.math.BigDecimal;
import java.util.List;
/**
* 物流任务 服务类
@ -63,4 +67,10 @@ public class TaskServiceImpl extends BaseServiceImpl<TaskMapper, Task> implement
public Task getBoxBarcode(String boxBarcode) {
return taskMapper.selectByBoxBarcode(boxBarcode);
}
@Override
public IPage<TaskVO> selectPage(IPage<TaskVO> page, TaskDto taskDto) {
List<TaskVO> taskVOList = taskMapper.selectEquipmentPage(page, taskDto);
return page.setRecords(taskVOList);
}
}

Loading…
Cancel
Save