箱条码与订单号的绑定与解绑

liweidong
绫Umbrella 1 month ago
parent aa1fbd06bd
commit e79bded7f2
  1. 8
      blade-service-api/blade-desk-api/src/main/java/org/springblade/desk/logistics/pojo/entity/Station.java
  2. 6
      blade-service-api/blade-desk-api/src/main/java/org/springblade/desk/logistics/pojo/entity/Task.java
  3. 4
      blade-service/blade-desk/pom.xml
  4. 15
      blade-service/blade-desk/src/main/java/org/springblade/desk/logistics/controller/OrderBoxController.java
  5. 2
      blade-service/blade-desk/src/main/java/org/springblade/desk/logistics/service/IOrderBoxService.java
  6. 277
      blade-service/blade-desk/src/main/java/org/springblade/desk/logistics/service/impl/IOrderBoxServiceImpl.java
  7. 173
      blade-service/blade-desk/src/main/java/org/springblade/desk/logistics/service/impl/OrderBoxServiceImpl.java

@ -23,12 +23,12 @@ public class Station extends BaseEntity {
private static final long serialVersionUID = 1L;
/**
* 状态常量占用
* 状态常量空闲
*/
public static final Integer STATUS_OCCUPIED = 0;
/**
* 状态常量空闲
* 状态常量占用
*/
public static final Integer STATUS_FREE = 1;
@ -56,9 +56,9 @@ public class Station extends BaseEntity {
private String stationCode;
/**
* 当前状态 0:占用 1:空闲
* 当前状态 0:空闲 1:占用
*/
@Schema(description = "当前状态 0:占用 1:空闲")
@Schema(description = "当前状态 0:空闲 1:占用")
private Integer stationStatus;
/**

@ -96,7 +96,11 @@ public class Task extends BaseEntity {
*/
@Schema(description = "临时库位ID")
private Long locationId;
/**
* 作业中心ID
*/
@Schema(description = "作业中心ID")
private Long wcId;
/**
* 当前状态 0:退回(超重) 1:站点 2:库位 3:等待 4:回库 5:结束
*/

@ -141,6 +141,10 @@
<version>1.9.13</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>com.qcloud</groupId>
<artifactId>cos_api</artifactId>
</dependency>
</dependencies>
<build>

@ -11,7 +11,8 @@ 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.logistics.service.OrderBoxService;
import org.springblade.desk.logistics.service.IOrderBoxService;
import org.springframework.web.bind.annotation.*;
import java.math.BigDecimal;
@ -28,7 +29,7 @@ import java.util.List;
@RequestMapping("/order")
@Tag(name = "订单箱子", description = "订单箱子称重接口")
public class OrderBoxController extends BladeController {
private final OrderBoxService orderBoxService;
private final IOrderBoxService iOrderBoxService;
private final IBsWorkCenterService bsWorkCenterService;
@ -51,7 +52,7 @@ public class OrderBoxController extends BladeController {
if (actualWeight == null || new BigDecimal(actualWeight).compareTo(BigDecimal.ZERO) < 0) {
return R.fail("实际重量必须为非负数");
}
return orderBoxService.upholdOrderPartWeight(cardNo,new BigDecimal(actualWeight));
return iOrderBoxService.upholdOrderPartWeight(cardNo,new BigDecimal(actualWeight));
}
@GetMapping("/bs-list")
@ -63,11 +64,11 @@ public class OrderBoxController extends BladeController {
public R getBSWORKCENTER(){
return R.data(bsWorkCenterService.list(new LambdaQueryWrapper<BsWorkCenterEntity>().eq(BsWorkCenterEntity::getIsDeleted, 0)));
}
@GetMapping("/box-binding")
@PostMapping("/box-binding")
@ApiOperationSupport(order = 3)
@Operation(
summary = "获取作业中心",
description = "获取当前作业中心名称"
summary = "绑定箱条码和订单",
description = "绑定箱条码和订单信息内容"
)
public R boxBinding(@RequestBody BoxBinding boxBinding){
// 1.参数合法性校验
@ -78,7 +79,7 @@ public class OrderBoxController extends BladeController {
return R.fail("箱条码不能为空");
}
return orderBoxService.boxBinding(boxBinding);
return iOrderBoxService.boxBinding(boxBinding);
}
}

@ -9,5 +9,7 @@ public interface IOrderBoxService {
R upholdOrderPartWeight(String cardNo, BigDecimal actualWeight);
R boxBinding(BoxBinding boxBinding);
R boxOrderUnbind(String boxBarcode);
}

@ -0,0 +1,277 @@
package org.springblade.desk.logistics.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import lombok.extern.slf4j.Slf4j;
import org.springblade.core.tool.api.R;
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.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import java.math.BigDecimal;
import java.util.*;
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;
/**
* 订单箱子 控制器
*
* @author qyl
* @since 2026-01-08
*/
@Service
@Slf4j
public class IOrderBoxServiceImpl implements IOrderBoxService {
private final IYieldOrderService iYieldOrderService;
private final ITaskService iTaskService;
private final IOrderBindService iOrderBindService;
private final IStationService iStationService;
private final ILocationService iLocationService;
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);
}
public IOrderBoxServiceImpl(IYieldOrderService iYieldOrderService, ITaskService iTaskService, IOrderBindService iOrderBindService, IStationService iStationService, ILocationService iLocationService) {
this.iYieldOrderService = iYieldOrderService;
this.iTaskService = iTaskService;
this.iOrderBindService = iOrderBindService;
this.iStationService = iStationService;
this.iLocationService = iLocationService;
}
@Override
public R upholdOrderPartWeight(String cardNo, BigDecimal actualWeight) {
log.info("接收到实际重量:{},对应的流程卡号:{}",actualWeight,cardNo);
//获取流程卡号
List<YieldOrder> list = iYieldOrderService.list(new QueryWrapper<YieldOrder>().eq("CARD_NO", cardNo).orderByDesc("UPDATE_TIME"));
//修改重量
list.get(0).setActualWeighing(actualWeight);
return iYieldOrderService.updateById(list.get(0))? R.success():R.fail("实际称重维护:卡号维护失败");
}
@Override
public R boxBinding(BoxBinding boxBinding) {
log.info("接收到箱绑定实际参数:{}", boxBinding);
// 1. 入参非空校验(基础防护)
if (boxBinding == null || boxBinding.getBoxBarcode() == null) {
log.warn("箱绑定参数为空或箱条码缺失");
return R.fail("箱条码不能为空");
}
String boxBarcode = boxBinding.getBoxBarcode();
// 2. 校验箱条码是否存在运行中的任务(封装为独立方法,提升可读性)
R taskCheckResult = checkBoxBarcodeRunningTask(boxBarcode);
if (!taskCheckResult.isSuccess()) {
return taskCheckResult;
}
// 3. 校验订单是否已绑定(封装为独立方法)
R orderCheckResult = checkOrderIdBoundStatus(boxBinding.getOrderIdList());
if (!orderCheckResult.isSuccess()) {
return orderCheckResult;
}
Long wcId = boxBinding.getWcId();
Task task = new Task();
task.setBoxBarcode(boxBinding.getBoxBarcode());
task.setWcId(wcId);
// 4. 获取当前站点位置
R location = getSiteLocation(task);
if (!location.isSuccess()) {
return location;
}
// 5. 保存记录到数据库中
task= (Task) location.getData();
task.setTaskStatus(Task.STATUS_START);
task.setCreateTime(new Date());
boolean orderBool = boxBinding.getOrderIdList() == null || boxBinding.getOrderIdList().size() == 0;
if (orderBool) {
task.setWeight(new BigDecimal(0));
}else {
task.setWeight(getWeightByOrderIdList(boxBinding.getOrderIdList()));
}
if (task.getWeight().compareTo(BigDecimal.valueOf(50)) < 0) {
R.fail("箱条码绑定的订单重量过重,请重新进行绑定");
}
if (!iTaskService.save(task)) {
R.fail("保存绑定箱条码异常");
}
if (orderBool) {
return R.success();
}else {
return saveOrderBindingList(task.getId(),boxBinding.getOrderIdList());
}
}
@Override
public R boxOrderUnbind(String boxBarcode) {
if (boxBarcode.isEmpty()) {
log.warn("箱绑定参数为空或箱条码缺失");
return R.fail("箱条码不能为空");
}
// 1. 根据箱条码查询数据
List<Task> taskList = iTaskService.list(
new LambdaQueryWrapper<Task>().eq(Task::getBoxBarcode, boxBarcode).in(Task::getTaskStatus,RUNNING_STATUSES)
);
for (Task task : taskList) {
if (task.getStationId()!=null&&task.getStationId()!=0) {
Station station = iStationService.getById(task.getStationId());
station.setStationStatus(STATUS_OCCUPIED);
iStationService.updateById(station);
}
if (task.getLocationId()!=null&&task.getLocationId()!=0) {
Location location = iLocationService.getById(task.getLocationId());
location.setLocationStatus(STATUS_OCCUPIED);
iLocationService.updateById(location);
}
List<OrderBind> orderBindList = iOrderBindService.list(new LambdaQueryWrapper<OrderBind>().eq(OrderBind::getTaskId, task.getId()));
if (orderBindList!=null&&orderBindList.size()!=0) {
for (OrderBind orderBind : orderBindList) {
orderBind.setBindingStatus(STATUS_UNBINDED);
iOrderBindService.updateById(orderBind);
}
}
task.setTaskStatus(STATUS_FINISHED);
iTaskService.updateById(task);
}
return R.success();
}
private R saveOrderBindingList(Long taskId, ArrayList<Long> orderIdList) {
ArrayList<OrderBind> orderBindList = new ArrayList<>();
for (Long orderId : orderIdList) {
OrderBind orderBind = new OrderBind();
orderBind.setBindingStatus(OrderBind.STATUS_BOUND);
orderBind.setTaskId(taskId);
orderBind.setOrderId(orderId);
orderBindList.add(orderBind);
}
if (iOrderBindService.saveBatch(orderBindList)) {
return R.success();
}else {
iTaskService.removeById(taskId);
return R.fail("订单绑定箱条码异常");
}
}
private BigDecimal getWeightByOrderIdList(ArrayList<Long> orderIdList) {
List<YieldOrder> orderList = iYieldOrderService.list(new LambdaQueryWrapper<YieldOrder>().in(YieldOrder::getId, orderIdList));
return orderList.stream()
.map(YieldOrder::getActualWeighing)
.filter(Objects::nonNull)
.reduce(BigDecimal.ZERO, BigDecimal::add);
}
private R getSiteLocation(Task task) {
List<Station> list = iStationService.list(new LambdaQueryWrapper<Station>().eq(Station::getWcId, task.getWcId()).eq(Station::getStationStatus, STATUS_OCCUPIED));
if (list!=null&&list.size()!=0) {
task.setStationId(list.get(0).getId());
Station station = list.get(0);
station.setStationStatus(Station.PRE_STATUS_OCCUPIED);
iStationService.updateById(station);
return R.data(task);
}
List<Location> locationList = iLocationService.list(new LambdaQueryWrapper<Location>().eq(Location::getLocationStatus, Location.STATUS_OCCUPIED));
if (locationList!=null&&locationList.size()!=0) {
task.setLocationId(locationList.get(0).getId());
Location location = locationList.get(0);
location.setLocationStatus(Location.STATUS_FREE);
iLocationService.updateById(location);
return R.data(task);
}
return R.fail("当前班次库位繁忙,请空闲后再试");
}
/**
* 校验箱条码是否存在运行中的任务
*/
private R checkBoxBarcodeRunningTask(String boxBarcode) {
// 查询箱条码对应的任务(MyBatis-Plus的list方法返回空列表,非null,无需判null)
List<Task> taskList = iTaskService.list(
new LambdaQueryWrapper<Task>().eq(Task::getBoxBarcode, boxBarcode)
);
// 无任务数据,直接通过校验
if (CollectionUtils.isEmpty(taskList)) {
return R.success();
}
// 判断是否有运行中的任务(流式操作简化,无冗余map)
boolean hasRunningTask = taskList.stream()
.map(Task::getTaskStatus)
.filter(status -> status != null) // 过滤null状态,避免NPE
.anyMatch(RUNNING_STATUSES::contains);
if (hasRunningTask) {
log.warn("箱条码{}存在运行中的任务,绑定异常", boxBarcode);
return R.fail("该箱条码在运行中,箱条码异常");
}
return R.success();
}
/**
* 校验订单号是否已绑定核心优化减少遍历次数流式收集数据
*/
private R checkOrderIdBoundStatus(List<Long> orderIdList) {
// 无订单号,直接通过校验
if (CollectionUtils.isEmpty(orderIdList)) {
return R.success();
}
// 查询订单绑定记录
List<OrderBind> orderBindList = iOrderBindService.list(
new LambdaQueryWrapper<OrderBind>().in(OrderBind::getOrderId, orderIdList)
);
if (CollectionUtils.isEmpty(orderBindList)) {
return R.success();
}
// 步骤1:过滤出已绑定的订单ID(流式收集,替代循环)
List<Long> boundOrderIds = orderBindList.stream()
.filter(orderBind -> OrderBind.STATUS_BOUND.equals(orderBind.getBindingStatus()))
.map(OrderBind::getOrderId)
.filter(orderId -> orderId != null) // 过滤null订单ID
.distinct() // 去重,避免重复查询
.collect(Collectors.toList());
// 无已绑定订单,直接通过
if (CollectionUtils.isEmpty(boundOrderIds)) {
return R.success();
}
// 步骤2:查询已绑定订单对应的流程卡号(流式收集,替代循环)
List<String> boundCardNos = iYieldOrderService.list(
new LambdaQueryWrapper<YieldOrder>().in(YieldOrder::getId, boundOrderIds)
).stream()
.map(YieldOrder::getCardNo)
.filter(cardNo -> cardNo != null) // 过滤null卡号
.collect(Collectors.toList());
// 构造异常信息并返回
String errorMsg = String.format("以下流程卡号处于绑定状态,绑定异常:{%s}", String.join(",", boundCardNos));
log.warn(errorMsg);
return R.fail(errorMsg);
}
}

@ -1,173 +0,0 @@
package org.springblade.desk.logistics.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import lombok.extern.slf4j.Slf4j;
import org.springblade.core.tool.api.R;
import org.springblade.desk.jobtransfer.service.ICertificateMaintenanceService;
import org.springblade.desk.logistics.pojo.entity.BoxBinding;
import org.springblade.desk.logistics.pojo.entity.OrderBind;
import org.springblade.desk.logistics.pojo.entity.Task;
import org.springblade.desk.logistics.service.OrderBindService;
import org.springblade.desk.logistics.service.OrderBoxService;
import org.springblade.desk.logistics.service.TaskService;
import org.springblade.desk.order.pojo.entity.YieldOrder;
import org.springblade.desk.order.service.IYieldOrderService;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
/**
* 订单箱子 控制器
*
* @author qyl
* @since 2026-01-08
*/
@Service
@Slf4j
public class OrderBoxServiceImpl implements OrderBoxService {
private final IYieldOrderService yieldOrderService;
private final TaskService taskService;
private final OrderBindService orderBindService;
private final OrderBindService orderBindService;
public OrderBoxServiceImpl(IYieldOrderService yieldOrderService, TaskService taskService, OrderBindService orderBindService) {
this.yieldOrderService = yieldOrderService;
this.taskService = taskService;
this.orderBindService = orderBindService;
}
private static final Set<Integer> RUNNING_STATUSES = new HashSet<>();
static {
RUNNING_STATUSES.add(Task.STATUS_STATION);
RUNNING_STATUSES.add(Task.STATUS_LOCATION);
RUNNING_STATUSES.add(Task.STATUS_WAITING);
RUNNING_STATUSES.add(Task.STATUS_BACK_TO_STORAGE);
}
private static final Set<Integer> ORDER_STATUSES = new HashSet<>();
static {
ORDER_STATUSES.add(OrderBind.STATUS_BOUND);
}
@Override
public R upholdOrderPartWeight(String cardNo, BigDecimal actualWeight) {
log.info("接收到实际重量:{},对应的流程卡号:{}",actualWeight,cardNo);
//获取流程卡号
List<YieldOrder> list = yieldOrderService.list(new QueryWrapper<YieldOrder>().eq("CARD_NO", cardNo).orderByDesc("UPDATE_TIME"));
//修改重量
list.get(0).setActualWeighing(actualWeight);
return yieldOrderService.updateById(list.get(0))? R.success():R.fail("实际称重维护:卡号维护失败");
}
@Override
public R boxBinding(BoxBinding boxBinding) {
log.info("接收到箱绑定实际参数:{}", boxBinding);
// 1. 入参非空校验(基础防护)
if (boxBinding == null || boxBinding.getBoxBarcode() == null) {
log.warn("箱绑定参数为空或箱条码缺失");
return R.fail("箱条码不能为空");
}
String boxBarcode = boxBinding.getBoxBarcode();
// 2. 校验箱条码是否存在运行中的任务(封装为独立方法,提升可读性)
R taskCheckResult = checkBoxBarcodeRunningTask(boxBarcode);
if (!taskCheckResult.isSuccess()) {
return taskCheckResult;
}
// 3. 校验订单是否已绑定(封装为独立方法)
R orderCheckResult = checkOrderIdBoundStatus(boxBinding.getOrderIdList());
if (!orderCheckResult.isSuccess()) {
return orderCheckResult;
}
//TODO:判断班次与库位记得写
//5.保存记录到数据库中
Task task = new Task();
task.setBoxBarcode(boxBinding.getBoxBarcode());
task.setTaskStatus(1);
task.set
return null;
}
/**
* 校验箱条码是否存在运行中的任务
*/
private R checkBoxBarcodeRunningTask(String boxBarcode) {
// 查询箱条码对应的任务(MyBatis-Plus的list方法返回空列表,非null,无需判null)
List<Task> taskList = taskService.list(
new LambdaQueryWrapper<Task>().eq(Task::getBoxBarcode, boxBarcode)
);
// 无任务数据,直接通过校验
if (CollectionUtils.isEmpty(taskList)) {
return R.success();
}
// 判断是否有运行中的任务(流式操作简化,无冗余map)
boolean hasRunningTask = taskList.stream()
.map(Task::getTaskStatus)
.filter(status -> status != null) // 过滤null状态,避免NPE
.anyMatch(RUNNING_STATUSES::contains);
if (hasRunningTask) {
log.warn("箱条码{}存在运行中的任务,绑定异常", boxBarcode);
return R.fail("该箱条码在运行中,箱条码异常");
}
return R.success();
}
/**
* 校验订单号是否已绑定核心优化减少遍历次数流式收集数据
*/
private R checkOrderIdBoundStatus(List<Long> orderIdList) {
// 无订单号,直接通过校验
if (CollectionUtils.isEmpty(orderIdList)) {
return R.success();
}
// 查询订单绑定记录
List<OrderBind> orderBindList = orderBindService.list(
new LambdaQueryWrapper<OrderBind>().in(OrderBind::getOrderId, orderIdList)
);
if (CollectionUtils.isEmpty(orderBindList)) {
return R.success();
}
// 步骤1:过滤出已绑定的订单ID(流式收集,替代循环)
List<Long> boundOrderIds = orderBindList.stream()
.filter(orderBind -> OrderBind.STATUS_BOUND.equals(orderBind.getBindingStatus()))
.map(OrderBind::getOrderId)
.filter(orderId -> orderId != null) // 过滤null订单ID
.distinct() // 去重,避免重复查询
.collect(Collectors.toList());
// 无已绑定订单,直接通过
if (CollectionUtils.isEmpty(boundOrderIds)) {
return R.success();
}
// 步骤2:查询已绑定订单对应的流程卡号(流式收集,替代循环)
List<String> boundCardNos = yieldOrderService.list(
new LambdaQueryWrapper<YieldOrder>().in(YieldOrder::getId, boundOrderIds)
).stream()
.map(YieldOrder::getCardNo)
.filter(cardNo -> cardNo != null) // 过滤null卡号
.collect(Collectors.toList());
// 构造异常信息并返回
String errorMsg = String.format("以下流程卡号处于绑定状态,绑定异常:{%s}", String.join(",", boundCardNos));
log.warn(errorMsg);
return R.fail(errorMsg);
}
}
Loading…
Cancel
Save