diff --git a/blade-service-api/blade-desk-api/src/main/java/org/springblade/desk/logistics/pojo/dto/BoxBindingDto.java b/blade-service-api/blade-desk-api/src/main/java/org/springblade/desk/logistics/pojo/dto/BoxBindingDto.java index a3d0a76d..8c7b4455 100644 --- a/blade-service-api/blade-desk-api/src/main/java/org/springblade/desk/logistics/pojo/dto/BoxBindingDto.java +++ b/blade-service-api/blade-desk-api/src/main/java/org/springblade/desk/logistics/pojo/dto/BoxBindingDto.java @@ -11,5 +11,5 @@ import java.util.ArrayList; public class BoxBindingDto { private String boxBarcode; private Long id; - private ArrayList orderIdList; + private ArrayList orderIdList; } diff --git a/blade-service/blade-desk/src/main/java/org/springblade/desk/logistics/controller/OrderBoxController.java b/blade-service/blade-desk/src/main/java/org/springblade/desk/logistics/controller/OrderBoxController.java index 49edfed7..6432c6e7 100644 --- a/blade-service/blade-desk/src/main/java/org/springblade/desk/logistics/controller/OrderBoxController.java +++ b/blade-service/blade-desk/src/main/java/org/springblade/desk/logistics/controller/OrderBoxController.java @@ -1,5 +1,6 @@ package org.springblade.desk.logistics.controller; +import com.alibaba.nacos.api.config.annotation.NacosValue; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.metadata.IPage; import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport; @@ -11,6 +12,7 @@ import io.swagger.v3.oas.annotations.media.Schema; import io.swagger.v3.oas.annotations.tags.Tag; import jodd.util.StringUtil; import lombok.AllArgsConstructor; +import lombok.Value; import org.springblade.core.boot.ctrl.BladeController; import org.springblade.core.mp.support.Condition; import org.springblade.core.mp.support.Query; @@ -110,15 +112,6 @@ public class OrderBoxController extends BladeController { } - /** - * 回调作业中心list - */ - @GetMapping("/return-warehouse-list") - @ApiOperationSupport(order = 6) - @Operation(summary = "回调作业中心list", description = "回调作业中心list") - public R inventoryReturnToWarehouseList() { - return iOrderBoxService.returnToWarehouseList(); - } /** * 回调作业中心list diff --git a/blade-service/blade-desk/src/main/java/org/springblade/desk/logistics/controller/PipelineController.java b/blade-service/blade-desk/src/main/java/org/springblade/desk/logistics/controller/PipelineController.java index a2b5c700..bdb0782e 100644 --- a/blade-service/blade-desk/src/main/java/org/springblade/desk/logistics/controller/PipelineController.java +++ b/blade-service/blade-desk/src/main/java/org/springblade/desk/logistics/controller/PipelineController.java @@ -82,10 +82,11 @@ public class PipelineController extends BladeController { ReturnToWarehouseDto returnToWarehouseDto = new ReturnToWarehouseDto(); returnToWarehouseDto.setBoxBarcode(boxBarcode); R wcIdR = iOrderBoxService.getWcId(boxBarcode); - if (!wcIdR.isSuccess()) { - return wcIdR; - } - returnToWarehouseDto.setEndWcId((Long) wcIdR.getData()); + Long wcId = (Long) wcIdR.getData(); + if (wcId==null) { + return R.fail("未查询到该箱条码的作业中心"); + } + returnToWarehouseDto.setEndWcId(wcId); R taskR = iOrderBoxService.saveTask(returnToWarehouseDto, false); if (!taskR.isSuccess()) { return taskR; 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 13886412..ccef6b71 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 @@ -1,5 +1,9 @@ package org.springblade.desk.logistics.service.impl; +import cn.hutool.http.HttpResponse; +import cn.hutool.http.HttpUtil; +import cn.hutool.json.JSONObject; +import cn.hutool.json.JSONUtil; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import lombok.extern.slf4j.Slf4j; @@ -15,7 +19,6 @@ import org.springblade.desk.logistics.utils.AgvTaskTypeUtil; import org.springblade.desk.order.pojo.entity.YieldOrder; import org.springblade.desk.order.service.IYieldOrderService; import org.springframework.stereotype.Service; -import org.springframework.util.Assert; import org.springframework.util.CollectionUtils; import java.math.BigDecimal; @@ -24,10 +27,17 @@ import java.util.stream.Collectors; import static org.springblade.desk.logistics.constant.AgvConstant.EQUIPMENT_TYPE_AGV; import static org.springblade.desk.logistics.pojo.entity.Station.*; +import static org.springblade.desk.logistics.utils.CollectionCheckUtil.findNotExistInBByStream; /** * 订单箱业务实现类 - * 核心职责:处理订单与箱条码的绑定/解绑、订单配件重量维护、任务/站点/库位状态管理等物流核心业务 + *

核心职责:

+ * * * @author qyl * @since 2026-01-08 @@ -35,410 +45,785 @@ import static org.springblade.desk.logistics.pojo.entity.Station.*; @Service @Slf4j public class IOrderBoxServiceImpl implements IOrderBoxService { + + // ========================== 常量定义区 ========================== /** - * 工单服务:处理工单重量、订单信息查询等 + * 输送线空箱数量查询接口地址(建议后续迁移至配置中心) */ - private final IYieldOrderService iYieldOrderService; + private static final String QUANTITY_OF_MATERIAL_BOXES_URL = "http://10.1.19.33:8686/api/emptyBoxCount"; + /** - * 任务服务:处理箱绑定任务的创建、状态更新、删除等 + * 箱条码绑定订单的最大重量阈值(单位:千克) */ - private final ITaskService iTaskService; + private static final BigDecimal MAX_BOX_WEIGHT_THRESHOLD = BigDecimal.valueOf(50); + /** - * 订单绑定服务:处理订单与任务的绑定关系维护 + * 任务运行中状态集合:用于判断箱条码是否存在未完成任务 + * 包含:任务启动(STATUS_START)、配送中(STATUS_CONVEYOR_END) */ - private final IOrderBindService iOrderBindService; + private static final Set RUNNING_TASK_STATUSES = new HashSet<>(); + + static { + // 初始化运行中任务状态 + RUNNING_TASK_STATUSES.add(Task.STATUS_START); // 任务启动状态 + RUNNING_TASK_STATUSES.add(Task.STATUS_CONVEYOR_END); // 配送完成状态(仍属运行中) + } + + // ========================== 依赖注入区 ========================== /** - * 站点服务:处理站点状态(占用/空闲)管理 + * 工单服务:提供工单查询、重量更新等能力 */ - private final IStationService iStationService; + private final IYieldOrderService yieldOrderService; + /** - * 库位服务:处理库位状态(占用/空闲)管理 + * 任务服务:提供任务CRUD、状态管理等能力 */ - private final ILocationService iLocationService; + private final ITaskService taskService; + /** + * 订单绑定服务:管理订单与箱条码的绑定关系 + */ + private final IOrderBindService orderBindService; - private final AgvTaskTypeUtil agvTaskTypeUtil; - private final IBsWorkCenterService bsWorkCenterService; - private final ITaskExecuteRecordService iTaskExecuteRecordService; + /** + * 站点服务:管理站点状态(空闲/占用)、站点查询 + */ + private final IStationService stationService; /** - * 任务运行中状态集合:包含任务从启动到待入库的所有中间状态 - * 用于判断箱条码是否存在未完成的运行任务 + * 库位服务:管理库位状态(空闲/占用)、库位查询 */ - private static final Set RUNNING_STATUSES = new HashSet<>(); + private final ILocationService locationService; - static { - // 初始化运行中任务状态 - RUNNING_STATUSES.add(Task.STATUS_START); // 任务启动 - RUNNING_STATUSES.add(Task.STATUS_CONVEYOR_END); // 配送 - } + /** + * AGV任务类型工具类:根据站点编码生成对应的AGV任务类型 + */ + private final AgvTaskTypeUtil agvTaskTypeUtil; - public IOrderBoxServiceImpl(IYieldOrderService iYieldOrderService, ITaskService iTaskService, IOrderBindService iOrderBindService, IStationService iStationService, ILocationService iLocationService, AgvTaskTypeUtil agvTaskTypeUtil, IBsWorkCenterService bsWorkCenterService, ITaskExecuteRecordService iTaskExecuteRecordService) { - this.iYieldOrderService = iYieldOrderService; - this.iTaskService = iTaskService; - this.iOrderBindService = iOrderBindService; - this.iStationService = iStationService; - this.iLocationService = iLocationService; - this.agvTaskTypeUtil = agvTaskTypeUtil; - this.bsWorkCenterService = bsWorkCenterService; - this.iTaskExecuteRecordService = iTaskExecuteRecordService; + /** + * 工位服务:提供工位基础信息查询 + */ + private final IBsWorkCenterService bsWorkCenterService; - } + /** + * 任务执行记录服务:处理AGV调度任务的生成与执行 + */ + private final ITaskExecuteRecordService taskExecuteRecordService; + // ========================== 构造器注入 ========================== /** - * 构造器注入依赖服务(替代@Autowired,符合Spring最佳实践) + * 构造器注入依赖(Spring官方推荐,避免@Autowired耦合) * - * @param iYieldOrderService 工单服务 - * @param iTaskService 任务服务 - * @param iOrderBindService 订单绑定服务 - * @param iStationService 站点服务 - * @param iLocationService 库位服务 + * @param yieldOrderService 工单服务 + * @param taskService 任务服务 + * @param orderBindService 订单绑定服务 + * @param stationService 站点服务 + * @param locationService 库位服务 + * @param agvTaskTypeUtil AGV任务类型工具类 + * @param bsWorkCenterService 工位服务 + * @param taskExecuteRecordService 任务执行记录服务 */ + public IOrderBoxServiceImpl(IYieldOrderService yieldOrderService, + ITaskService taskService, + IOrderBindService orderBindService, + IStationService stationService, + ILocationService locationService, + AgvTaskTypeUtil agvTaskTypeUtil, + IBsWorkCenterService bsWorkCenterService, + ITaskExecuteRecordService taskExecuteRecordService) { + this.yieldOrderService = yieldOrderService; + this.taskService = taskService; + this.orderBindService = orderBindService; + this.stationService = stationService; + this.locationService = locationService; + this.agvTaskTypeUtil = agvTaskTypeUtil; + this.bsWorkCenterService = bsWorkCenterService; + this.taskExecuteRecordService = taskExecuteRecordService; + } + // ========================== 核心业务方法 ========================== /** * 维护订单配件实际重量 - * 功能:根据流程卡号更新对应工单的实际称重数据 + *

根据流程卡号查询最新的工单记录,更新其实际称重字段

* * @param cardNo 流程卡号(唯一标识工单) - * @param actualWeight 实际称重值(单位:业务约定,如千克) + * @param actualWeight 实际称重值(单位:千克) * @return R 操作结果 - * - 成功:R.success() - * - 失败:R.fail(),携带具体失败原因 + *
    + *
  • 成功:R.success() - 重量更新完成
  • + *
  • 失败:R.fail() - 携带具体失败原因(卡号为空/不存在/更新失败)
  • + *
*/ @Override - public R upholdOrderPartWeight(String cardNo, BigDecimal actualWeight) { - log.info("接收到实际重量:{},对应的流程卡号:{}", actualWeight, cardNo); - // 根据流程卡号查询工单(按更新时间倒序,取最新记录) - List list = iYieldOrderService.list(new QueryWrapper().eq("CARD_NO", cardNo).orderByDesc("UPDATE_TIME")); - - // 更新最新工单的实际重量 - list.get(0).setActualWeighing(actualWeight); + public R upholdOrderPartWeight(String cardNo, BigDecimal actualWeight) { + log.info("【订单重量维护】开始处理 - 流程卡号:{},实际重量:{}kg", cardNo, actualWeight); - // 执行更新并返回结果 - return iYieldOrderService.updateById(list.get(0)) ? R.success() : R.fail("实际称重维护:卡号维护失败"); - } + // 1. 参数合法性校验 + if (Objects.isNull(cardNo) || cardNo.isBlank()) { + log.warn("【订单重量维护】流程卡号为空,操作终止"); + return R.fail("流程卡号不能为空"); + } + if (Objects.isNull(actualWeight) || actualWeight.compareTo(BigDecimal.ZERO) < 0) { + log.warn("【订单重量维护】实际重量非法:{}kg(需≥0)", actualWeight); + return R.fail("实际重量必须大于等于0"); + } + // 2. 查询最新工单记录(按更新时间倒序) + List orderList = yieldOrderService.list( + new QueryWrapper() + .eq("CARD_NO", cardNo) + .orderByDesc("UPDATE_TIME") + ); + if (CollectionUtils.isEmpty(orderList)) { + log.warn("【订单重量维护】流程卡号{}未查询到对应工单", cardNo); + return R.fail("流程卡号不存在"); + } + // 3. 更新工单实际重量 + YieldOrder latestOrder = orderList.get(0); + latestOrder.setActualWeighing(actualWeight); + boolean updateResult = yieldOrderService.updateById(latestOrder); + // 4. 返回处理结果 + if (updateResult) { + log.info("【订单重量维护】流程卡号{}重量更新成功,新重量:{}kg", cardNo, actualWeight); + return R.success(); + } else { + log.error("【订单重量维护】流程卡号{}重量更新失败", cardNo); + return R.fail("实际称重维护:卡号维护失败"); + } + } /** * 箱条码与订单绑定核心方法 - * 流程:参数校验 → 任务状态校验 → 订单绑定状态校验 → 任务创建 → 订单绑定 + *

核心流程:参数校验 → 订单有效性校验 → 箱任务状态校验 → 订单绑定状态校验 → 重量校验 → 绑定关系保存

* - * @param boxBinding 箱绑定参数(包含箱条码、订单ID列表、工位ID等) + * @param boxBinding 箱绑定参数DTO(包含箱条码、订单ID列表等) * @return R 绑定结果 - * - 成功:R.success() - * - 失败:R.fail(),携带具体失败原因(如参数为空、订单已绑定、重量超限等) + *
    + *
  • 成功:R.success() - 绑定关系创建完成
  • + *
  • 失败:R.fail() - 携带具体失败原因(参数为空/订单已绑定/重量超限等)
  • + *
*/ @Override - public R boxBinding(BoxBindingDto boxBinding) { - log.info("接收到箱绑定实际参数:{}", boxBinding); + public R boxBinding(BoxBindingDto boxBinding) { + log.info("【箱条码绑定】开始处理 - 绑定参数:{}", boxBinding); - // 1. 入参非空校验(基础防护) - if (boxBinding == null || boxBinding.getBoxBarcode() == null) { - log.warn("箱绑定参数为空或箱条码缺失"); - return R.fail("箱条码不能为空"); - } - if (boxBinding.getOrderIdList()==null||boxBinding.getOrderIdList().isEmpty()) { - return R.fail("订单不能为空"); + // 1. 基础参数校验 + R paramCheckResult = validateBoxBindingParams(boxBinding); + if (!paramCheckResult.isSuccess()) { + return paramCheckResult; } String boxBarcode = boxBinding.getBoxBarcode(); + List orderCardNoList = boxBinding.getOrderIdList(); - // 2. 校验箱条码是否存在运行中的任务(避免重复绑定) - R taskCheckResult = checkBoxBarcodeRunningTask(boxBarcode); - if (!taskCheckResult.isSuccess()) { - return taskCheckResult; + // 2. 订单有效性校验 + R orderValidResult = validateOrderExist(orderCardNoList); + if (!orderValidResult.isSuccess()) { + return orderValidResult; } + List yieldOrderList = (List) orderValidResult.getData(); + List orderIdList = yieldOrderList.stream() + .map(YieldOrder::getId) + .collect(Collectors.toList()); - // 3. 校验订单是否已绑定(避免订单重复绑定) - R orderCheckResult = checkOrderIdBoundStatus(boxBinding.getOrderIdList()); - if (!orderCheckResult.isSuccess()) { - return orderCheckResult; + // 3. 校验箱条码是否存在运行中任务 + R boxTaskCheckResult = checkBoxBarcodeRunningTask(boxBarcode); + if (!boxTaskCheckResult.isSuccess()) { + return boxTaskCheckResult; } - // 4. 计算订单总重量(无订单则重量为0) - boolean orderBool = boxBinding.getOrderIdList() == null || boxBinding.getOrderIdList().size() == 0; - if (!orderBool) { - BigDecimal weightByOrderIdList = getWeightByOrderIdList(boxBinding.getOrderIdList()); - if (weightByOrderIdList.compareTo(BigDecimal.valueOf(50)) > 0) { - return R.fail("箱条码绑定的订单重量过重,请重新进行绑定"); - } - } - // 5. 保存箱订单表 - return saveOrderBindingList(boxBinding.getBoxBarcode(), boxBinding.getOrderIdList()); - } - /** - * 批量保存订单与任务的绑定关系 - * 核心:创建订单绑定记录并批量插入,插入失败则回滚任务(删除已创建的任务) - * - * @param boxBarcode 箱条码 - * @param orderIdList 订单ID列表 - * @return R 保存结果 - * - 成功:R.success() - * - 失败:R.fail(),删除任务并返回异常信息 - */ - private R saveOrderBindingList(String boxBarcode, ArrayList orderIdList) { - ArrayList orderBindList = new ArrayList<>(); - if (orderIdList.isEmpty()) { - return R.fail("订单id不能为空"); - } - // 构建订单绑定记录 - for (Long orderId : orderIdList) { - OrderBind orderBind = new OrderBind(); - orderBind.setBindingStatus(OrderBind.STATUS_BOUND); // 绑定状态:已绑定 - orderBind.setBoxBarcode(boxBarcode); // 关联箱条码 - orderBind.setOrderId(orderId); // 关联订单ID - orderBindList.add(orderBind); + // 4. 校验订单是否已绑定 + R orderBindCheckResult = checkOrderIdBoundStatus(orderIdList); + if (!orderBindCheckResult.isSuccess()) { + return orderBindCheckResult; } - // 批量插入绑定记录,失败则删除任务 - if (iOrderBindService.saveBatch(orderBindList)) { - return R.success(); - } else { - return R.fail("订单绑定箱条码异常"); + // 5. 订单重量校验(超限则拒绝绑定) + BigDecimal totalWeight = calculateOrderTotalWeight(orderIdList); + if (totalWeight.compareTo(MAX_BOX_WEIGHT_THRESHOLD) > 0) { + String errorMsg = String.format("箱条码%s绑定的订单总重量%.2fkg,超过最大阈值%.2fkg", + boxBarcode, totalWeight, MAX_BOX_WEIGHT_THRESHOLD); + log.warn("【箱条码绑定】{}", errorMsg); + return R.fail(errorMsg + ",请重新进行绑定"); } + + // 6. 保存绑定关系 + return saveOrderBoxBinding(boxBarcode, new ArrayList<>(orderIdList)); } + /** - * 根据订单ID列表计算订单总重量 - * 逻辑:查询订单对应的工单 → 累加实际称重值(过滤null值) + * 查询回库可选工位列表 + *

查询空闲状态的站点关联工位,默认添加输送线回库选项

* - * @param orderIdList 订单ID列表 - * @return BigDecimal 订单总重量(单位:业务约定,如千克) + * @return R> 工位VO列表(含默认输送线选项) */ - private BigDecimal getWeightByOrderIdList(List orderIdList) { - // 查询订单对应的工单列表 - log.info("查询订单list:{}",orderIdList); - List orderList = iYieldOrderService.list(new LambdaQueryWrapper().in(YieldOrder::getId, orderIdList)); - log.info("查询订单orderList:{}",orderIdList); - // 流式累加实际称重值(过滤null,初始值为0) - return orderList.stream() - .map(YieldOrder::getActualWeighing) - .filter(Objects::nonNull) - .reduce(BigDecimal.ZERO, BigDecimal::add); - } - + @Override + public R> returnToWarehouseList() { + log.info("【回库工位查询】开始查询空闲站点关联工位"); + // 1. 查询空闲状态的站点 + List freeStationList = stationService.list( + new LambdaQueryWrapper().eq(Station::getStationStatus, STATUS_FREE) + ); - @Override - public R returnToWarehouseList() { - List stationList = iStationService.list(new LambdaQueryWrapper().eq(Station::getStationStatus, STATUS_FREE)); - ArrayList bsWorkCenterVOList = new ArrayList<>(); - BsWorkCenterVO bsWorkCenterVO = new BsWorkCenterVO(); - bsWorkCenterVO.setId(0l); - bsWorkCenterVO.setWcName(DROPOFF_CONVEYOR_LINE_NAME); - if (!stationList.isEmpty()) { - List list = stationList.stream().map(Station::getWcId).distinct().collect(Collectors.toList()); - List bwList = bsWorkCenterService.getByIds(list); - if (!bwList.isEmpty()) { - bwList.forEach(s -> { - bsWorkCenterVOList.add(s); - }); + // 2. 构建返回列表(默认添加输送线回库选项) + List resultList = new ArrayList<>(); + BsWorkCenterVO conveyorVO = new BsWorkCenterVO(); + conveyorVO.setId(0L); + conveyorVO.setWcName(DROPOFF_CONVEYOR_LINE_NAME); + resultList.add(conveyorVO); + + // 3. 补充空闲站点关联的工位信息 + if (!CollectionUtils.isEmpty(freeStationList)) { + List wcIdList = freeStationList.stream() + .map(Station::getWcId) + .distinct() + .collect(Collectors.toList()); + List wcVOList = bsWorkCenterService.getByIds(wcIdList); + if (!CollectionUtils.isEmpty(wcVOList)) { + resultList.addAll(wcVOList); + log.info("【回库工位查询】查询到{}个空闲工位", wcVOList.size()); } - } - return R.data(bsWorkCenterVOList); - } + log.info("【回库工位查询】完成,共返回{}个工位选项", resultList.size()); + return R.data(resultList); + } + /** + * 站点状态接收(置为空闲) + *

根据站点编码更新站点状态为空闲,释放站点资源

+ * + * @param stationCode 站点编码(唯一标识站点) + * @return R 操作结果 + *
    + *
  • 成功:R.success() - 站点状态更新为空闲
  • + *
  • 失败:R.fail() - 携带具体失败原因(编码为空/不存在/更新失败)
  • + *
+ */ @Override - public R receive(String stationCode) { - if (stationCode.isEmpty()) { + public R receive(String stationCode) { + log.info("【站点状态接收】开始处理 - 站点编码:{}", stationCode); + + // 1. 参数校验 + if (Objects.isNull(stationCode) || stationCode.isBlank()) { + log.warn("【站点状态接收】站点编码为空,操作终止"); return R.fail("站点编码不能为空"); } - List stationList = iStationService.list(new LambdaQueryWrapper().eq(Station::getStationCode, stationCode)); - if (stationList.isEmpty()) { + + // 2. 查询站点 + List stationList = stationService.list( + new LambdaQueryWrapper().eq(Station::getStationCode, stationCode) + ); + if (CollectionUtils.isEmpty(stationList)) { + log.warn("【站点状态接收】站点编码{}不存在", stationCode); return R.fail("站点编码不存在"); } - stationList.get(0).setStationStatus(STATUS_FREE); - if (iStationService.updateById(stationList.get(0))) { + + // 3. 更新站点状态为空闲 + Station targetStation = stationList.get(0); + targetStation.setStationStatus(STATUS_FREE); + boolean updateResult = stationService.updateById(targetStation); + + // 4. 返回结果 + if (updateResult) { + log.info("【站点状态接收】站点编码{}已置为空闲", stationCode); return R.success(); + } else { + log.error("【站点状态接收】站点编码{}状态更新失败", stationCode); + return R.fail("站点切换空闲异常"); } - return R.fail("站点切换空闲异常"); } + /** + * 创建回库任务(核心方法) + *

核心流程:参数校验 → 起始站点处理 → 箱状态校验 → 资源分配(站点/库位)→ 任务保存 → AGV调度

+ * + * @param returnToWarehouseDto 回库任务参数DTO + * @param agvSend 是否发送AGV调度任务(true=发送,false=仅创建任务) + * @return R 任务创建结果 + *
    + *
  • 成功:R.success() - 任务创建完成(AGV调度成功)
  • + *
  • 失败:R.fail() - 携带具体失败原因(参数错误/资源不足/AGV调度失败)
  • + *
+ */ @Override - public R saveTask(ReturnToWarehouseDto returnToWarehouseDto,Boolean agvSend) { - if (returnToWarehouseDto.getEndWcId()==null) { - R.fail("结束位置不能都为空"); - } - String stationCode=""; - String endStationCode=""; - if (returnToWarehouseDto.getStartStationCode()!=null&&!returnToWarehouseDto.getStartStationCode().isEmpty()) { - List stationList = iStationService.list(new LambdaQueryWrapper().eq(Station::getStationCode, returnToWarehouseDto.getStartStationCode())); - if (stationList.isEmpty()) { - return R.fail("站点编码不存在"); - } - if (!stationList.get(0).getStationStatus().equals(STATUS_FREE)) { - return R.fail("站点编码不存在"); - } - stationCode= returnToWarehouseDto.getStartStationCode(); - }else { - stationCode=Station.PICKUP_CONVEYOR_LINE; + public R saveTask(ReturnToWarehouseDto returnToWarehouseDto, Boolean agvSend) { + log.info("【回库任务创建】开始处理 - DTO:{},是否发送AGV:{}", returnToWarehouseDto, agvSend); + + // 1. 基础参数校验 + if (Objects.isNull(returnToWarehouseDto)) { + log.warn("【回库任务创建】参数DTO为空,操作终止"); + return R.fail("回库参数不能为空"); + } + if (Objects.isNull(returnToWarehouseDto.getEndWcId())) { + log.warn("【回库任务创建】结束工位ID为空,操作终止"); + return R.fail("结束位置不能为空"); } + agvSend = Objects.nonNull(agvSend) ? agvSend : false; // 默认不发送AGV + + // 2. 初始化变量 + String startStationCode = ""; + String endStationCode = ""; Task task = new Task(); - //判断箱条码是否为空,如果不为空判断是否在使用 - if (returnToWarehouseDto.getBoxBarcode()!=null&&!returnToWarehouseDto.getBoxBarcode().isEmpty()) { - R taskCheckResult = checkBoxBarcodeRunningTask(returnToWarehouseDto.getBoxBarcode()); - if (!taskCheckResult.isSuccess()) { - return taskCheckResult; - } + // 3. 处理起始站点编码 + R startStationResult = handleStartStationCode(returnToWarehouseDto); + if (!startStationResult.isSuccess()) { + return startStationResult; } - task.setBoxBarcode(returnToWarehouseDto.getBoxBarcode().isEmpty()?"":returnToWarehouseDto.getBoxBarcode()); - task.setWcId(returnToWarehouseDto.getEndWcId()); - if (returnToWarehouseDto.getEndWcId()==0) { - //todo:查看输送线回库 + startStationCode = (String) startStationResult.getData(); + + // 4. 箱条码状态校验(非空时) + String boxBarcode = returnToWarehouseDto.getBoxBarcode(); + if (Objects.nonNull(boxBarcode) && !boxBarcode.isBlank()) { + R boxTaskCheckResult = checkBoxBarcodeRunningTask(boxBarcode); + if (!boxTaskCheckResult.isSuccess()) { + return boxTaskCheckResult; + } + task.setBoxBarcode(boxBarcode); + } else { + task.setBoxBarcode(""); + } + + // 5. 设置结束工位ID并处理不同回库类型 + Long endWcId = returnToWarehouseDto.getEndWcId(); + task.setWcId(endWcId); + if (endWcId == 0) { + // 5.1 输送线回库:校验空箱数量 +// R conveyorCheckResult = checkConveyorEmptyBoxCount(); +// if (!conveyorCheckResult.isSuccess()) { +// return conveyorCheckResult; +// } task.setWcId(0L); - endStationCode= DROPOFF_CONVEYOR_LINE; - }else { - // 5. 获取当前可用的站点/库位并分配 - R locationResult = getSiteLocation(task); + endStationCode = DROPOFF_CONVEYOR_LINE; + } else { + // 5.2 普通工位回库:分配站点/库位 + R locationResult = allocateSiteOrLocation(task); if (!locationResult.isSuccess()) { return locationResult; } - // 6. 完善任务信息并保存 task = (Task) locationResult.getData(); - log.info("task:"+task.toString()); - if (task.getStationId()==null) { - if (agvSend) { - List locationList = iLocationService.list(new LambdaQueryWrapper().eq(Location::getId, task.getLocationId())); - if (!CollectionUtils.isEmpty(locationList)) { - Location location = locationList.get(0); - location.setLocationStatus(Location.STATUS_FREE); - iLocationService.updateById(location); - - } - return R.fail("结束站点被占用"); - } + log.info("【回库任务创建】资源分配完成 - 任务:{}", task); - }else { - Station station = iStationService.getById(task.getStationId()); - if (station==null) { - return R.fail("结束站点不存在"); - } - endStationCode=station.getStationCode(); + // 5.3 校验结束站点状态 + R endStationResult = validateEndStationStatus(task, agvSend); + if (!endStationResult.isSuccess()) { + return endStationResult; } + endStationCode = (String) endStationResult.getData(); } - task.setTaskStatus(Task.STATUS_START); // 设置任务初始状态为启动 - task.setCreateTime(new Date()); // 设置任务创建时间 - task.setCreateUser(AuthUtil.getUserId()); - if (!returnToWarehouseDto.getBoxBarcode().isEmpty()) { - List orderBindList = iOrderBindService.list(new LambdaQueryWrapper().eq(OrderBind::getBoxBarcode, returnToWarehouseDto.getBoxBarcode()).eq(false, OrderBind::getBindingStatus, OrderBind.STATUS_UNBINDED)); - log.info("需要承重的list:"+orderBindList); - if (orderBindList==null||orderBindList.isEmpty()) { - task.setWeight(new BigDecimal(0)); - }else { - List orderIdsList = orderBindList.stream() - .filter(Objects::nonNull) - .map(OrderBind::getOrderId) - .filter(Objects::nonNull) - .collect(Collectors.toList()); - task.setWeight(getWeightByOrderIdList(orderIdsList)); - } + // 6. 完善任务基础信息 + task = completeTaskBasicInfo(task, returnToWarehouseDto); - }else { - task.setWeight(new BigDecimal(0)); - } - if (!iTaskService.save(task)) { + // 7. 保存任务 + if (!taskService.save(task)) { + log.error("【回库任务创建】任务保存失败 - 任务:{}", task); return R.fail("保存任务表异常"); } + + // 8. 发送AGV调度任务(可选) if (agvSend) { - String taskType = agvTaskTypeUtil.getTaskTypeByPositions(stationCode,endStationCode); - boolean agvResult = iTaskExecuteRecordService.genAgvSchedulingTask( - taskType, stationCode, endStationCode, EQUIPMENT_TYPE_AGV, task); - if (agvResult) { - return R.success(); - }else { - iTaskService.removeById(task); - return R.fail("AGV小车调用异常"); - } - }else { - return R.success(); + return sendAgvSchedulingTask(task, startStationCode, endStationCode); } - + log.info("【回库任务创建】任务创建成功(未发送AGV)- 任务ID:{}", task.getId()); + return R.success(); } + /** + * 根据箱条码查询绑定订单对应的工位ID + *

查询箱条码绑定的有效订单,返回第一个订单关联的工位ID

+ * + * @param boxBarcode 箱条码 + * @return R 工位ID结果 + *
    + *
  • 成功:R.data(Long) - 工位ID
  • + *
  • 失败:R.fail() - 箱条码未绑定任何订单
  • + *
+ */ @Override - public R getWcId(String boxBarcode) { - List orderBindList = iOrderBindService.list(new LambdaQueryWrapper().eq(OrderBind::getBoxBarcode, boxBarcode).eq(OrderBind::getBindingStatus, OrderBind.STATUS_BOUND)); - if (orderBindList==null||orderBindList.isEmpty()) { + public R getWcId(String boxBarcode) { + log.info("【工位ID查询】开始处理 - 箱条码:{}", boxBarcode); + + // 1. 参数校验 + if (Objects.isNull(boxBarcode) || boxBarcode.isBlank()) { + log.warn("【工位ID查询】箱条码为空,操作终止"); + return R.fail("箱条码不能为空"); + } + + // 2. 查询绑定的订单记录 + List orderBindList = orderBindService.list( + new LambdaQueryWrapper() + .eq(OrderBind::getBoxBarcode, boxBarcode) + .eq(OrderBind::getBindingStatus, OrderBind.STATUS_BOUND) + ); + if (CollectionUtils.isEmpty(orderBindList)) { + log.warn("【工位ID查询】箱条码{}未绑定任何订单", boxBarcode); return R.fail("该箱子没有绑定数据"); } - Long wcId=iYieldOrderService.getWcId(orderBindList.get(0).getOrderId()); + + // 3. 查询工位ID + Long orderId = orderBindList.get(0).getOrderId(); + Long wcId = yieldOrderService.getWcId(orderId); + log.info("【工位ID查询】箱条码{}对应的工位ID:{}", boxBarcode, wcId); + return R.data(wcId); } + // ========================== 私有工具方法 ========================== + + /** + * 校验箱绑定参数合法性 + * + * @param boxBinding 箱绑定参数DTO + * @return R 校验结果 + */ + private R validateBoxBindingParams(BoxBindingDto boxBinding) { + if (Objects.isNull(boxBinding)) { + return R.fail("绑定参数不能为空"); + } + if (Objects.isNull(boxBinding.getBoxBarcode()) || boxBinding.getBoxBarcode().isBlank()) { + log.warn("【箱条码绑定】箱条码为空"); + return R.fail("箱条码不能为空"); + } + if (CollectionUtils.isEmpty(boxBinding.getOrderIdList())) { + log.warn("【箱条码绑定】订单列表为空"); + return R.fail("订单不能为空"); + } + return R.success(); + } + + /** + * 校验订单是否存在(根据流程卡号) + * + * @param orderCardNoList 流程卡号列表 + * @return R 校验结果(成功返回订单列表,失败返回错误信息) + */ + private R validateOrderExist(List orderCardNoList) { + List yieldOrderList = yieldOrderService.list( + new LambdaQueryWrapper().in(YieldOrder::getCardNo, orderCardNoList) + ); + + // 订单不存在校验 + if (CollectionUtils.isEmpty(yieldOrderList)) { + return R.fail("流程卡号输入错误"); + } + + // 未知订单校验 + if (yieldOrderList.size() != orderCardNoList.size()) { + List notExistList = findNotExistInBByStream(yieldOrderList, orderCardNoList); + return R.fail("以下订单未知:" + notExistList); + } + + return R.data(yieldOrderList); + } + + /** + * 计算订单列表总重量 + *

累加订单的实际称重值,过滤null值,初始值为0

+ * + * @param orderIdList 订单ID列表 + * @return BigDecimal 订单总重量(单位:千克) + */ + private BigDecimal calculateOrderTotalWeight(List orderIdList) { + log.info("【订单重量计算】开始计算订单ID列表{}的总重量", orderIdList); + + List orderList = yieldOrderService.list( + new LambdaQueryWrapper().in(YieldOrder::getId, orderIdList) + ); + log.info("【订单重量计算】查询到订单列表:{}", orderList); + + return orderList.stream() + .map(YieldOrder::getActualWeighing) + .filter(Objects::nonNull) + .reduce(BigDecimal.ZERO, BigDecimal::add); + } + + /** + * 保存订单与箱条码的绑定关系 + * + * @param boxBarcode 箱条码 + * @param orderIdList 订单ID列表 + * @return R 保存结果 + */ + private R saveOrderBoxBinding(String boxBarcode, ArrayList orderIdList) { + if (CollectionUtils.isEmpty(orderIdList)) { + return R.fail("订单id不能为空"); + } + + // 构建绑定关系列表 + List bindList = orderIdList.stream() + .map(orderId -> { + OrderBind bind = new OrderBind(); + bind.setBindingStatus(OrderBind.STATUS_BOUND); + bind.setBoxBarcode(boxBarcode); + bind.setOrderId(orderId); + return bind; + }) + .collect(Collectors.toList()); + + // 批量保存 + boolean saveResult = orderBindService.saveBatch(bindList); + if (saveResult) { + log.info("【箱条码绑定】箱{}绑定{}个订单成功", boxBarcode, orderIdList.size()); + return R.success(); + } else { + log.error("【箱条码绑定】箱{}绑定订单失败", boxBarcode); + return R.fail("订单绑定箱条码异常"); + } + } + + /** + * 处理起始站点编码(默认赋值/有效性校验) + * + * @param dto 回库任务参数DTO + * @return R 处理后的起始站点编码 + */ + private R handleStartStationCode(ReturnToWarehouseDto dto) { + String startStationCode = dto.getStartStationCode(); + if (Objects.nonNull(startStationCode) && !startStationCode.isBlank()) { + // 校验站点是否存在 + List stationList = stationService.list( + new LambdaQueryWrapper().eq(Station::getStationCode, startStationCode) + ); + if (CollectionUtils.isEmpty(stationList)) { + return R.fail("站点编码不存在"); + } + // 校验站点是否空闲 + if (!stationList.get(0).getStationStatus().equals(STATUS_FREE)) { + return R.fail("站点非空闲状态,无法使用"); + } + return R.data(startStationCode); + } else { + // 默认赋值为取料输送线 + return R.data(PICKUP_CONVEYOR_LINE); + } + } /** - * 获取当前工位可用的站点/库位并分配 - * 优先级:先分配站点 → 站点无可用则分配库位 → 均无则返回失败 + * 校验输送线空箱数量(调用外部接口) * - * @param task 任务对象(包含工位ID) - * @return R 分配结果 - * - 成功:R.data(task),任务对象已填充站点/库位ID - * - 失败:R.fail(),提示库位繁忙 + * @return R 校验结果 */ - private R getSiteLocation(Task task) { - // 1. 查询当前工位可用的站点(状态为占用的站点) - List list = iStationService.list(new LambdaQueryWrapper().eq(Station::getWcId, task.getWcId()).eq(Station::getStationStatus, STATUS_FREE)); - if (!CollectionUtils.isEmpty(list)) { - task.setStationId(list.get(0).getId()); // 分配第一个可用站点 - // 更新站点状态为预占用(锁定站点) - Station station = list.get(0); - station.setStationStatus(Station.PRE_STATUS_OCCUPIED); - iStationService.updateById(station); + private R checkConveyorEmptyBoxCount() { + HttpResponse response = null; + try { + // 调用空箱数量接口 + response = HttpUtil.createGet(QUANTITY_OF_MATERIAL_BOXES_URL) + .timeout(30000) + .execute(); + + // 校验HTTP状态码 + if (!response.isOk()) { + log.error("【空箱查询】接口调用失败 - 状态码:{},响应体:{}", + response.getStatus(), response.body()); + return R.fail("调用输送线接口获取空料箱数量失败"); + } + + // 解析响应数据 + JSONObject json = JSONUtil.parseObj(response.body()); + Long emptyBoxCount = json.getLong("data"); + if (emptyBoxCount == 0) { + log.warn("【空箱查询】输送线空箱数量为0,无法回库"); + return R.fail("输送线空箱子已满请稍后再试"); + } + + log.info("【空箱查询】输送线空箱数量:{}", emptyBoxCount); + return R.success(); + } catch (Exception e) { + log.error("【空箱查询】接口调用异常", e); + return R.fail("调用输送线接口异常:" + e.getMessage()); + } finally { + // 关闭响应流,避免资源泄漏 + if (Objects.nonNull(response)) { + response.close(); + } + } + } + + /** + * 分配站点/库位资源(优先级:站点 → 库位) + * + * @param task 任务对象(含工位ID) + * @return R 分配后的任务对象 + */ + private R allocateSiteOrLocation(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); + task.setStationId(station.getId()); + // 锁定站点(预占用) + station.setStationStatus(PRE_STATUS_OCCUPIED); + stationService.updateById(station); + log.info("【资源分配】工位{}分配到空闲站点{}", task.getWcId(), station.getId()); return R.data(task); } - // 2. 站点无可用则查询可用库位(状态为占用的库位) - List locationList = iLocationService.list(new LambdaQueryWrapper().eq(Location::getLocationStatus, Location.STATUS_FREE)); - if (!CollectionUtils.isEmpty(locationList)) { - task.setLocationId(locationList.get(0).getId()); // 分配第一个可用库位 - // 更新库位状态为空闲(锁定库位) - Location location = locationList.get(0); + // 2. 尝试分配空闲库位 + List freeLocationList = locationService.list( + new LambdaQueryWrapper().eq(Location::getLocationStatus, STATUS_FREE) + ); + if (!CollectionUtils.isEmpty(freeLocationList)) { + Location location = freeLocationList.get(0); + task.setLocationId(location.getId()); + // 锁定库位(占用) location.setLocationStatus(Location.STATUS_OCCUPIED); - iLocationService.updateById(location); + if (!locationService.updateById(location)) { + log.info("【资源分配】分配到空闲库位{}修改失败", location.getId()); + return R.fail("库位修改状态失败"); + } + log.info("【资源分配】分配到空闲库位{}", location.getId()); return R.data(task); } - // 3. 站点/库位均无可用 + // 3. 无可用资源 + log.warn("【资源分配】工位{}无可用站点/库位", task.getWcId()); return R.fail("当前班次库位繁忙,请空闲后再试"); } + /** + * 校验结束站点状态 + * + * @param task 任务对象 + * @param agvSend 是否发送AGV + * @return R 结束站点编码(成功)/错误信息(失败) + */ + private R validateEndStationStatus(Task task, Boolean agvSend) { + if (Objects.isNull(task.getStationId())) { + // 无站点ID:校验库位状态并返回失败 + if (agvSend) { + List locationList = locationService.list( + new LambdaQueryWrapper().eq(Location::getId, task.getLocationId()) + ); + if (!CollectionUtils.isEmpty(locationList)) { + Location location = locationList.get(0); + location.setLocationStatus(Location.STATUS_FREE); + locationService.updateById(location); + log.info("【资源释放】库位{}已释放", location.getId()); + } + return R.fail("结束站点被占用"); + } + return R.data(""); + } else { + // 有站点ID:校验站点存在性并锁定 + Station station = stationService.getById(task.getStationId()); + if (Objects.isNull(station)) { + return R.fail("结束站点不存在"); + } + // 锁定站点(预占用)- 修复原代码空指针问题(先判空再更新) + station.setStationStatus(PRE_STATUS_OCCUPIED); + stationService.updateById(station); + return R.data(station.getStationCode()); + } + } + + /** + * 完善任务基础信息(状态/创建时间/重量等) + * + * @param task 任务对象 + * @param dto 回库任务参数DTO + * @return Task 完善后的任务对象 + */ + private Task completeTaskBasicInfo(Task task, ReturnToWarehouseDto dto) { + // 基础信息 + task.setTaskStatus(Task.STATUS_START); + task.setCreateTime(new Date()); + task.setCreateUser(AuthUtil.getUserId()); + // 任务重量计算 + String boxBarcode = dto.getBoxBarcode(); + BigDecimal taskWeight = BigDecimal.ZERO; + if (Objects.nonNull(boxBarcode) && !boxBarcode.isBlank()) { + List bindList = orderBindService.list( + new LambdaQueryWrapper() + .eq(OrderBind::getBoxBarcode, boxBarcode) + .eq(false, OrderBind::getBindingStatus, OrderBind.STATUS_UNBINDED) + ); + log.info("【任务重量计算】箱{}绑定订单列表:{}", boxBarcode, bindList); + + if (!CollectionUtils.isEmpty(bindList)) { + List orderIdList = bindList.stream() + .filter(Objects::nonNull) + .map(OrderBind::getOrderId) + .filter(Objects::nonNull) + .collect(Collectors.toList()); + taskWeight = calculateOrderTotalWeight(orderIdList); + } + } + task.setWeight(taskWeight); + return task; + } + + /** + * 发送AGV调度任务 + * + * @param task 任务对象 + * @param startStationCode 起始站点编码 + * @param endStationCode 结束站点编码 + * @return R 调度结果 + */ + private R sendAgvSchedulingTask(Task task, String startStationCode, String endStationCode) { + try { + // 获取AGV任务类型 + String taskType = agvTaskTypeUtil.getTaskTypeByPositions(startStationCode, endStationCode); + // 发送调度任务 + boolean agvResult = taskExecuteRecordService.genAgvSchedulingTask( + taskType, startStationCode, endStationCode, EQUIPMENT_TYPE_AGV, task + ); + + if (agvResult) { + log.info("【AGV调度】任务{}调度成功 - 类型:{}", task.getId(), taskType); + return R.success(); + } else { + // 调度失败:回滚任务 + taskService.removeById(task); + log.error("【AGV调度】任务{}调度失败,已回滚", task.getId()); + return R.fail("AGV小车调用异常"); + } + } catch (Exception e) { + // 异常处理:回滚任务 + taskService.removeById(task); + log.error("【AGV调度】任务{}调度异常,已回滚", task.getId(), e); + return R.fail("AGV小车调用异常:" + e.getMessage()); + } + } /** * 校验箱条码是否存在运行中的任务 - * 核心:避免同一箱条码同时存在多个未完成的绑定任务 + *

避免同一箱条码同时存在多个未完成任务

* * @param boxBarcode 箱条码 * @return R 校验结果 - * - 成功:R.success()(无运行中任务) - * - 失败:R.fail()(存在运行中任务) */ - private R checkBoxBarcodeRunningTask(String boxBarcode) { - // 查询箱条码对应的所有任务 - List taskList = iTaskService.list( + private R checkBoxBarcodeRunningTask(String boxBarcode) { + // 查询箱条码关联任务 + List taskList = taskService.list( new LambdaQueryWrapper().eq(Task::getBoxBarcode, boxBarcode) ); - // 无任务数据,直接通过校验 + // 无任务直接通过 if (CollectionUtils.isEmpty(taskList)) { return R.success(); } - // 判断是否有运行中的任务(流式操作,简化逻辑) + // 判断是否存在运行中任务 boolean hasRunningTask = taskList.stream() .map(Task::getTaskStatus) - .filter(status -> status != null) // 过滤null状态,避免空指针 - .anyMatch(RUNNING_STATUSES::contains); + .filter(Objects::nonNull) + .anyMatch(RUNNING_TASK_STATUSES::contains); if (hasRunningTask) { - log.warn("箱条码{}存在运行中的任务,绑定异常", boxBarcode); + log.warn("【箱条码校验】箱{}存在运行中任务,禁止绑定", boxBarcode); return R.fail("该箱条码在运行中,箱条码异常"); } return R.success(); @@ -446,50 +831,47 @@ public class IOrderBoxServiceImpl implements IOrderBoxService { /** * 校验订单是否已绑定 - * 核心:避免同一订单被重复绑定到不同箱条码 + *

避免同一订单被重复绑定到不同箱条码

* * @param orderIdList 订单ID列表 * @return R 校验结果 - * - 成功:R.success()(无已绑定订单) - * - 失败:R.fail()(存在已绑定订单,返回对应流程卡号) */ - private R checkOrderIdBoundStatus(List orderIdList) { - // 无订单号,直接通过校验 + private R checkOrderIdBoundStatus(List orderIdList) { if (CollectionUtils.isEmpty(orderIdList)) { return R.success(); } - // 查询订单对应的绑定记录 - List orderBindList = iOrderBindService.list( + // 查询订单绑定记录 + List bindList = orderBindService.list( new LambdaQueryWrapper().in(OrderBind::getOrderId, orderIdList) ); - if (CollectionUtils.isEmpty(orderBindList)) { + if (CollectionUtils.isEmpty(bindList)) { return R.success(); } - // 过滤出已绑定的订单ID(去重,避免重复提示) - List boundOrderIds = orderBindList.stream() - .filter(orderBind -> OrderBind.STATUS_BOUND.equals(orderBind.getBindingStatus())) + // 过滤已绑定的订单ID + List boundOrderIds = bindList.stream() + .filter(bind -> OrderBind.STATUS_BOUND.equals(bind.getBindingStatus())) .map(OrderBind::getOrderId) - .filter(orderId -> orderId != null) + .filter(Objects::nonNull) .distinct() .collect(Collectors.toList()); - // 无已绑定订单,直接通过 if (CollectionUtils.isEmpty(boundOrderIds)) { return R.success(); } - // 查询已绑定订单对应的流程卡号,构造异常信息 - List boundCardNos = iYieldOrderService.list( + // 查询已绑定订单的流程卡号 + List boundCardNos = yieldOrderService.list( new LambdaQueryWrapper().in(YieldOrder::getId, boundOrderIds) ).stream() .map(YieldOrder::getCardNo) - .filter(cardNo -> cardNo != null) + .filter(Objects::nonNull) .collect(Collectors.toList()); - String errorMsg = String.format("以下流程卡号处于绑定状态,绑定异常:{%s}", String.join(",", boundCardNos)); - log.warn(errorMsg); + String errorMsg = String.format("以下流程卡号处于绑定状态,绑定异常:{%s}", + String.join(",", boundCardNos)); + log.warn("【订单绑定校验】{}", errorMsg); return R.fail(errorMsg); } } \ No newline at end of file diff --git a/blade-service/blade-desk/src/main/java/org/springblade/desk/logistics/service/impl/StorageMonitoringServiceImpl.java b/blade-service/blade-desk/src/main/java/org/springblade/desk/logistics/service/impl/StorageMonitoringServiceImpl.java index e7198290..b093cc5a 100644 --- a/blade-service/blade-desk/src/main/java/org/springblade/desk/logistics/service/impl/StorageMonitoringServiceImpl.java +++ b/blade-service/blade-desk/src/main/java/org/springblade/desk/logistics/service/impl/StorageMonitoringServiceImpl.java @@ -116,7 +116,6 @@ public class StorageMonitoringServiceImpl implements IStorageMonitoringService { // ========== 步骤2.1:查询对应工位的待库位任务(按创建时间升序) ========== List taskList = taskService.list( new LambdaQueryWrapper() - .eq(Task::getTaskStatus, Task.STATUS_CONVEYOR_END) // 任务状态:待库位 .eq(Task::getTaskStatus, Task.STATUS_TEMPORARY_STORAGE) // 任务状态:待库位 .eq(Task::getWcId, station.getWcId()) // 匹配当前站点的工位ID .orderByAsc(Task::getCreateTime) // 按创建时间升序,优先处理最早创建的任务 @@ -154,6 +153,8 @@ public class StorageMonitoringServiceImpl implements IStorageMonitoringService { } else { // 更新库位状态为空闲 location.setLocationStatus(Location.STATUS_FREE); + log.info("【仓储监控】库位ID:{} - 更新的参数{}", locationId,location); + boolean updateResult = locationService.updateById(location); if (updateResult) { log.info("【仓储监控】库位ID:{} - 状态更新为空闲成功", locationId); diff --git a/blade-service/blade-desk/src/main/java/org/springblade/desk/logistics/utils/CollectionCheckUtil.java b/blade-service/blade-desk/src/main/java/org/springblade/desk/logistics/utils/CollectionCheckUtil.java index 94a32736..bd23c802 100644 --- a/blade-service/blade-desk/src/main/java/org/springblade/desk/logistics/utils/CollectionCheckUtil.java +++ b/blade-service/blade-desk/src/main/java/org/springblade/desk/logistics/utils/CollectionCheckUtil.java @@ -1,7 +1,11 @@ package org.springblade.desk.logistics.utils; -import java.util.Collection; -import java.util.Map; +import cn.hutool.db.sql.Order; +import org.springblade.desk.order.pojo.entity.YieldOrder; +import org.springframework.util.CollectionUtils; + +import java.util.*; +import java.util.stream.Collectors; public class CollectionCheckUtil { /** @@ -32,5 +36,30 @@ public class CollectionCheckUtil { // 不支持的集合类型 throw new IllegalArgumentException("不支持的集合类型:" + targetCollection.getClass().getName()); } + /** + * 方式2:流式操作方式(简洁优雅,Java8+推荐) + * @param a 实体类集合 + * @param b 字符串集合 + * @return b中不存在于a的字符串列表 + */ + public static List findNotExistInBByStream(List a, Collection b) { + // 1. 校验入参 + if (CollectionUtils.isEmpty(a) || CollectionUtils.isEmpty(b)) { + return CollectionUtils.isEmpty(b) ? new ArrayList<>() : new ArrayList<>(b); + } + + // 2. 提取a中的对比字段,生成Set(过滤null) + Set aCodeSet = a.stream() + .filter(Objects::nonNull) // 过滤null实体 + .map(YieldOrder::getCardNo) // 提取要对比的字段(替换为你的实际字段) + .filter(Objects::nonNull) // 过滤null字段值 + .collect(Collectors.toSet()); + + // 3. 筛选b中不在aCodeSet的元素 + return b.stream() + .filter(Objects::nonNull) // 过滤b中的null值 + .filter(str -> !aCodeSet.contains(str)) + .collect(Collectors.toList()); + } } diff --git a/blade-service/blade-desk/src/main/java/org/springblade/desk/order/service/impl/YieldOrderServiceImpl.java b/blade-service/blade-desk/src/main/java/org/springblade/desk/order/service/impl/YieldOrderServiceImpl.java index 577cfe59..289e1344 100644 --- a/blade-service/blade-desk/src/main/java/org/springblade/desk/order/service/impl/YieldOrderServiceImpl.java +++ b/blade-service/blade-desk/src/main/java/org/springblade/desk/order/service/impl/YieldOrderServiceImpl.java @@ -717,7 +717,12 @@ public class YieldOrderServiceImpl extends BaseServiceImpl list = list(new LambdaQueryWrapper().eq(YieldOrder::getId, orderId)); + if (list!=null&&!list.isEmpty()) { + return list.get(0).getWorkCenterId(); + } + return null; } /**