diff --git a/blade-service-api/blade-desk-api/src/main/java/org/springblade/desk/logistics/pojo/entity/Location.java b/blade-service-api/blade-desk-api/src/main/java/org/springblade/desk/logistics/pojo/entity/Location.java
index ae4fc3ad..a3e18ca3 100644
--- a/blade-service-api/blade-desk-api/src/main/java/org/springblade/desk/logistics/pojo/entity/Location.java
+++ b/blade-service-api/blade-desk-api/src/main/java/org/springblade/desk/logistics/pojo/entity/Location.java
@@ -38,7 +38,10 @@ public class Location extends BaseEntity {
*/
public static final Integer STATUS_FREE = 0;
-
+ /**
+ * 状态常量:初始架
+ */
+ public static final Integer ORIGINAL_RACK = 1;
/**
* 库名称
*/
diff --git a/blade-service-api/blade-desk-api/src/main/java/org/springblade/desk/logistics/pojo/entity/Station.java b/blade-service-api/blade-desk-api/src/main/java/org/springblade/desk/logistics/pojo/entity/Station.java
index fd9cc486..b2ab3c49 100644
--- a/blade-service-api/blade-desk-api/src/main/java/org/springblade/desk/logistics/pojo/entity/Station.java
+++ b/blade-service-api/blade-desk-api/src/main/java/org/springblade/desk/logistics/pojo/entity/Station.java
@@ -37,6 +37,15 @@ public class Station extends BaseEntity {
*/
public static final Integer PRE_STATUS_OCCUPIED = 2;
+ /**
+ * 状态常量:收发-只收
+ */
+ public static final Integer RECEIVE_ONLY = 0;
+ /**
+ * 状态常量:收发-同层
+ */
+ public static final Integer SAME_LAYER = 2;
+
/**
* 取货输送线 站点类型常量
*/
diff --git a/blade-service/blade-desk/src/main/java/org/springblade/desk/logistics/service/impl/IOrderBoxServiceImpl.java b/blade-service/blade-desk/src/main/java/org/springblade/desk/logistics/service/impl/IOrderBoxServiceImpl.java
index ccef6b71..0e22d284 100644
--- a/blade-service/blade-desk/src/main/java/org/springblade/desk/logistics/service/impl/IOrderBoxServiceImpl.java
+++ b/blade-service/blade-desk/src/main/java/org/springblade/desk/logistics/service/impl/IOrderBoxServiceImpl.java
@@ -26,8 +26,9 @@ import java.util.*;
import java.util.stream.Collectors;
import static org.springblade.desk.logistics.constant.AgvConstant.EQUIPMENT_TYPE_AGV;
+import static org.springblade.desk.logistics.pojo.entity.Location.ORIGINAL_RACK;
import static org.springblade.desk.logistics.pojo.entity.Station.*;
-import static org.springblade.desk.logistics.utils.CollectionCheckUtil.findNotExistInBByStream;
+import static org.springblade.desk.logistics.utils.CollectionCheckUtil.*;
/**
* 订单箱业务实现类
@@ -111,6 +112,7 @@ public class IOrderBoxServiceImpl implements IOrderBoxService {
private final ITaskExecuteRecordService taskExecuteRecordService;
// ========================== 构造器注入 ==========================
+
/**
* 构造器注入依赖(Spring官方推荐,避免@Autowired耦合)
*
@@ -248,6 +250,7 @@ public class IOrderBoxServiceImpl implements IOrderBoxService {
log.warn("【箱条码绑定】{}", errorMsg);
return R.fail(errorMsg + ",请重新进行绑定");
}
+ // 6.
// 6. 保存绑定关系
return saveOrderBoxBinding(boxBarcode, new ArrayList<>(orderIdList));
@@ -257,7 +260,7 @@ public class IOrderBoxServiceImpl implements IOrderBoxService {
* 查询回库可选工位列表
*
查询空闲状态的站点关联工位,默认添加输送线回库选项
*
- * @return R> 工位VO列表(含默认输送线选项)
+ * @return R> 工位VO列表(含默认输送线选项)
*/
@Override
public R> returnToWarehouseList() {
@@ -401,7 +404,7 @@ public class IOrderBoxServiceImpl implements IOrderBoxService {
endStationCode = DROPOFF_CONVEYOR_LINE;
} else {
// 5.2 普通工位回库:分配站点/库位
- R> locationResult = allocateSiteOrLocation(task);
+ R> locationResult = allocateSiteOrLocation(startStationCode, task);
if (!locationResult.isSuccess()) {
return locationResult;
}
@@ -518,6 +521,15 @@ public class IOrderBoxServiceImpl implements IOrderBoxService {
List notExistList = findNotExistInBByStream(yieldOrderList, orderCardNoList);
return R.fail("以下订单未知:" + notExistList);
}
+ //判断wcid是否一致
+ boolean allFieldSame = isAllFieldSame(yieldOrderList, YieldOrder::getWorkCenterId);
+ if (!allFieldSame) {
+ return R.fail("订单所属的作业中心不一致");
+ }
+ if (yieldOrderList.get(0).getWorkCenterId() == null) {
+ return R.fail("订单所属的作业中心不能为空");
+ }
+
return R.data(yieldOrderList);
}
@@ -595,7 +607,11 @@ public class IOrderBoxServiceImpl implements IOrderBoxService {
}
// 校验站点是否空闲
if (!stationList.get(0).getStationStatus().equals(STATUS_FREE)) {
- return R.fail("站点非空闲状态,无法使用");
+ return R.fail("起始站点非空闲状态,无法使用");
+ }
+ // 校验站点是否可以发送数据
+ if (stationList.get(0).getStatus().equals(RECEIVE_ONLY)) {
+ return R.fail("起始站点站码无法当开始站点编码");
}
return R.data(startStationCode);
} else {
@@ -648,18 +664,33 @@ public class IOrderBoxServiceImpl implements IOrderBoxService {
/**
* 分配站点/库位资源(优先级:站点 → 库位)
*
- * @param task 任务对象(含工位ID)
+ * @param startStationCode
+ * @param task 任务对象(含工位ID)
* @return R 分配后的任务对象
*/
- private R allocateSiteOrLocation(Task task) {
+ private R allocateSiteOrLocation(String startStationCode, Task task) {
// 1. 尝试分配空闲站点
List freeStationList = stationService.list(
new LambdaQueryWrapper()
.eq(Station::getWcId, task.getWcId())
.eq(Station::getStationStatus, STATUS_FREE)
);
+
if (!CollectionUtils.isEmpty(freeStationList)) {
- Station station = freeStationList.get(0);
+ Station station = null;
+ String stationPosition = "";
+ if (station.getStatus() == SAME_LAYER) {
+ Station startStation = stationService.list(new LambdaQueryWrapper().eq(Station::getStationCode, startStationCode)).get(0);
+ stationPosition = startStation.getStationPosition();
+ station = findByField(freeStationList, "stationPosition", stationPosition);
+
+
+ } else {
+ station = freeStationList.get(0);
+ }
+ if (station == null) {
+ return R.fail("当前班次" + stationPosition + "楼层库位繁忙,请空闲后再试");
+ }
task.setStationId(station.getId());
// 锁定站点(预占用)
station.setStationStatus(PRE_STATUS_OCCUPIED);
@@ -670,7 +701,9 @@ public class IOrderBoxServiceImpl implements IOrderBoxService {
// 2. 尝试分配空闲库位
List freeLocationList = locationService.list(
- new LambdaQueryWrapper().eq(Location::getLocationStatus, STATUS_FREE)
+ new LambdaQueryWrapper()
+ .ne(Location::getStatus, ORIGINAL_RACK)
+ .eq(Location::getLocationStatus, STATUS_FREE)
);
if (!CollectionUtils.isEmpty(freeLocationList)) {
Location location = freeLocationList.get(0);
@@ -693,8 +726,8 @@ public class IOrderBoxServiceImpl implements IOrderBoxService {
/**
* 校验结束站点状态
*
- * @param task 任务对象
- * @param agvSend 是否发送AGV
+ * @param task 任务对象
+ * @param agvSend 是否发送AGV
* @return R 结束站点编码(成功)/错误信息(失败)
*/
private R> validateEndStationStatus(Task task, Boolean agvSend) {
@@ -710,6 +743,7 @@ public class IOrderBoxServiceImpl implements IOrderBoxService {
locationService.updateById(location);
log.info("【资源释放】库位{}已释放", location.getId());
}
+ taskService.removeById(task);
return R.fail("结束站点被占用");
}
return R.data("");
@@ -717,6 +751,7 @@ public class IOrderBoxServiceImpl implements IOrderBoxService {
// 有站点ID:校验站点存在性并锁定
Station station = stationService.getById(task.getStationId());
if (Objects.isNull(station)) {
+ taskService.removeById(task);
return R.fail("结束站点不存在");
}
// 锁定站点(预占用)- 修复原代码空指针问题(先判空再更新)
@@ -746,7 +781,7 @@ public class IOrderBoxServiceImpl implements IOrderBoxService {
List bindList = orderBindService.list(
new LambdaQueryWrapper()
.eq(OrderBind::getBoxBarcode, boxBarcode)
- .eq(false, OrderBind::getBindingStatus, OrderBind.STATUS_UNBINDED)
+ .ne(OrderBind::getBindingStatus, OrderBind.STATUS_UNBINDED)
);
log.info("【任务重量计算】箱{}绑定订单列表:{}", boxBarcode, bindList);
@@ -787,12 +822,18 @@ public class IOrderBoxServiceImpl implements IOrderBoxService {
} else {
// 调度失败:回滚任务
taskService.removeById(task);
+ List stationList = stationService.list(new LambdaQueryWrapper().eq(Station::getId, task.getStationId()));
+ stationList.get(0).setStationStatus(STATUS_FREE);
+ stationService.updateById(stationList.get(0));
log.error("【AGV调度】任务{}调度失败,已回滚", task.getId());
return R.fail("AGV小车调用异常");
}
} catch (Exception e) {
// 异常处理:回滚任务
taskService.removeById(task);
+ List stationList = stationService.list(new LambdaQueryWrapper().eq(Station::getId, task.getStationId()));
+ stationList.get(0).setStationStatus(STATUS_FREE);
+ stationService.updateById(stationList.get(0));
log.error("【AGV调度】任务{}调度异常,已回滚", task.getId(), e);
return R.fail("AGV小车调用异常:" + e.getMessage());
}
diff --git a/blade-service/blade-desk/src/main/java/org/springblade/desk/logistics/service/impl/OrderBindServiceImpl.java b/blade-service/blade-desk/src/main/java/org/springblade/desk/logistics/service/impl/OrderBindServiceImpl.java
index 6c7edc69..ffb37cf6 100644
--- a/blade-service/blade-desk/src/main/java/org/springblade/desk/logistics/service/impl/OrderBindServiceImpl.java
+++ b/blade-service/blade-desk/src/main/java/org/springblade/desk/logistics/service/impl/OrderBindServiceImpl.java
@@ -119,7 +119,7 @@ public class OrderBindServiceImpl extends BaseServiceImpl orderBindList = list(new LambdaQueryWrapper()
.eq(OrderBind::getBoxBarcode, boxBarcode)
- .eq(false,OrderBind::getBindingStatus, STATUS_UNBINDED));
+ .ne(OrderBind::getBindingStatus, STATUS_UNBINDED));
// 优化:提示信息更精准
if (orderBindList.isEmpty()) {
diff --git a/blade-service/blade-desk/src/main/java/org/springblade/desk/logistics/service/impl/TaskExecuteRecordServiceImpl.java b/blade-service/blade-desk/src/main/java/org/springblade/desk/logistics/service/impl/TaskExecuteRecordServiceImpl.java
index c7df7b20..83870d7b 100644
--- a/blade-service/blade-desk/src/main/java/org/springblade/desk/logistics/service/impl/TaskExecuteRecordServiceImpl.java
+++ b/blade-service/blade-desk/src/main/java/org/springblade/desk/logistics/service/impl/TaskExecuteRecordServiceImpl.java
@@ -151,18 +151,30 @@ public class TaskExecuteRecordServiceImpl extends BaseServiceImpl 实体类型
+ * @param 字段值类型
+ * @return true=全部一致 / false=存在不一致 / 空集合/单元素集合返回true
+ */
+ public static boolean isAllFieldSame(List entityList, Function fieldExtractor) {
+ // 1. 边界校验:空集合或单元素集合,默认一致
+ if (CollectionUtils.isEmpty(entityList) || entityList.size() == 1) {
+ return true;
+ }
+
+ // 2. 校验字段获取器非空
+ if (fieldExtractor == null) {
+ throw new IllegalArgumentException("字段获取器不能为空");
+ }
+
+ // 3. 取第一个元素的字段值作为基准
+ V baseValue = fieldExtractor.apply(entityList.get(0));
+
+ // 4. 遍历所有元素,对比字段值
+ for (T entity : entityList) {
+ V currentValue = fieldExtractor.apply(entity);
+ // Objects.equals自动处理null值对比(null == null 返回true)
+ if (!Objects.equals(baseValue, currentValue)) {
+ return false;
+ }
+ }
+
+ return true;
+ }
/**
* 判断指定字段的值是否存在于目标集合中
*
@@ -62,4 +100,57 @@ public class CollectionCheckUtil {
.collect(Collectors.toList());
}
+
+ /**
+ * 从实体类集合中查找指定属性等于指定值的对象
+ * @param collection 实体类集合
+ * @param fieldName 要匹配的属性名(注意:区分大小写,要和实体类中的属性名一致)
+ * @param value 要匹配的属性值
+ * @param 实体类泛型
+ * @return 匹配的对象,未找到则返回 null
+ */
+ public static T findByField(Collection collection, String fieldName, Object value) {
+ // 空值校验
+ if (collection == null || collection.isEmpty() || fieldName == null || fieldName.isEmpty()) {
+ return null;
+ }
+
+ // 遍历集合中的每个对象
+ for (T obj : collection) {
+ if (obj == null) {
+ continue;
+ }
+
+ try {
+ // 通过反射获取属性(包括私有属性)
+ Field field = obj.getClass().getDeclaredField(fieldName);
+ // 设置可访问私有属性
+ field.setAccessible(true);
+ // 获取对象的该属性值
+ Object fieldValue = field.get(obj);
+
+ // 匹配属性值(处理 null 值的情况)
+ if (value == null) {
+ if (fieldValue == null) {
+ return obj; // 属性值和目标值都为 null,匹配成功
+ }
+ } else {
+ if (value.equals(fieldValue)) {
+ return obj; // 属性值匹配成功,返回该对象
+ }
+ }
+
+ } catch (NoSuchFieldException e) {
+ // 属性名不存在,抛出明确的异常提示
+ throw new IllegalArgumentException("实体类中不存在属性:" + fieldName, e);
+ } catch (IllegalAccessException e) {
+ // 属性访问失败
+ throw new RuntimeException("无法访问属性:" + fieldName, e);
+ }
+ }
+
+ // 遍历完未找到匹配的对象,返回 null
+ return null;
+ }
+
}