no message

main
HUOJIN\92525 2026-01-08 23:29:10 +08:00
parent 31d08765ab
commit 3559b73ee1
11 changed files with 256 additions and 30 deletions

View File

@ -6,6 +6,7 @@ import org.cpte.modules.agvTask.entity.AgvTask;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import java.util.List;
import java.util.Map;
/**
* @Description: AGV
@ -65,4 +66,10 @@ public interface AgvTaskMapper extends BaseMapper<AgvTask> {
*/
@Select(value = "select * from data_agv_task where business_detail_id = #{businessId} and type='INBOUND' and agv_vendor = 'TES' ")
AgvTask queryByBusinessId(@Param("businessId") Long businessId);
/**
*
*/
@Select(value = "select end_code,count(end_code) from data_agv_task where type='OUTBOUND' and status in (1,2) and agv_vendor='TES' group by end_code")
List<Map<String, Integer>> pointTaskCountMap();
}

View File

@ -4,7 +4,6 @@ import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.cpte.modules.shipping.mapper.PickMapper;
import org.cpte.modules.shipping.service.IPickService;
import org.cpte.modules.shipping.service.ITaskService;
import org.jeecg.common.constant.CommonConstant;
import org.jeecg.modules.base.service.BaseCommonService;
import org.quartz.Job;
@ -37,7 +36,7 @@ public class AllocateJob implements Job {
private static final int MAX_CACHE_SIZE = 1000;
// 记录上次分配的索引
private int lastProcessedIndex = -1;
private static int lastProcessedIndex = -1;
@Override
public void execute(JobExecutionContext jobExecutionContext) {

View File

@ -6,7 +6,6 @@ import org.cpte.modules.agvTask.mapper.AgvTaskMapper;
import org.cpte.modules.constant.GeneralConstant;
import org.cpte.modules.constant.enums.AgvStatusEnum;
import org.cpte.modules.constant.enums.AgvVendorEnum;
import org.cpte.modules.hikAgv.service.IHikAgvService;
import org.cpte.modules.shipping.service.ITaskService;
import org.cpte.modules.tesAgv.service.ITesAgvService;
import org.quartz.Job;
@ -31,13 +30,20 @@ public class TesAgvJob implements Job {
@Override
public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
//生成出库AGV出库任务
//1.分配工作站
long startTime = System.currentTimeMillis();
iTaskService.allocationStation();
long endTime = System.currentTimeMillis();
log.info("分配工作站耗时:{}ms", endTime - startTime);
//2.生成TES任务
long startTime2 = System.currentTimeMillis();
iTaskService.generateAgvTask();
long endTime2 = System.currentTimeMillis();
log.info("生成AGV出库任务耗时{}ms", endTime2 - startTime2);
// 查询待执行任务
// 3.下发任务TES
List<AgvTask> agvTaskList = agvTaskMapper.queryAgvTaskList(AgvStatusEnum.CREATED.getValue(), AgvVendorEnum.TES.getValue());
if (agvTaskList.isEmpty()) {
return;

View File

@ -2,10 +2,7 @@ package org.cpte.modules.shipping.entity;
import java.io.Serializable;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.baomidou.mybatisplus.annotation.TableLogic;
import com.baomidou.mybatisplus.annotation.*;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.fasterxml.jackson.databind.ser.std.ToEmptyObjectSerializer;
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
@ -68,6 +65,7 @@ public class PickDetail implements Serializable {
@Excel(name = "容器", width = 15)
@Schema(description = "容器")
@JsonSerialize(using = ToStringSerializer.class)
@TableField(fill = FieldFill.INSERT_UPDATE)
private java.lang.Long stockId;
/**

View File

@ -17,12 +17,12 @@ import java.util.List;
*/
public interface TaskMapper extends BaseMapper<Task> {
/**
* AGVTask
* Task
*
* @return List<Pick>
*/
@Select("SELECT * FROM data_task WHERE agv_task_id is null order by create_time ")
List<Task> queryUnallocatedTask();
List<Task> queryUnIssuedTask();
@Select("SELECT * FROM data_task WHERE agv_task_id = #{agvTaskId} ")
List<Task> queryByAgvTask(@Param("agvTaskId") Long agvTaskId);
@ -33,4 +33,12 @@ public interface TaskMapper extends BaseMapper<Task> {
List<Task> queryTaskByMainId(@Param("pickId")Long pickId);
List<Task> queryByInventoryIds(@Param("inventoryIds") List<Long> inventoryIds);
/**
* Task
*
* @return List<Pick>
*/
@Select("SELECT * FROM data_task WHERE agv_task_id is null and to_point_id is null")
List<Task> queryUnallocatedTask();
}

View File

@ -65,5 +65,8 @@ public interface ITaskService extends IService<Task> {
*/
List<Task> queryTaskByMainId(Long id);
/**
*
*/
void allocationStation();
}

View File

@ -5,13 +5,20 @@ import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.shiro.SecurityUtils;
import org.cpte.modules.agvTask.entity.AgvTask;
import org.cpte.modules.agvTask.mapper.AgvTaskMapper;
import org.cpte.modules.agvTask.service.IAgvTaskService;
import org.cpte.modules.base.entity.*;
import org.cpte.modules.base.service.IPointService;
import org.cpte.modules.constant.enums.*;
import org.cpte.modules.conveyorLine.vo.Station;
import org.cpte.modules.inventory.entity.Inventory;
import org.cpte.modules.inventory.service.IInventoryService;
import org.cpte.modules.inventoryLog.service.IInventoryLogService;
import org.cpte.modules.shipping.entity.Pick;
import org.cpte.modules.shipping.entity.PickDetail;
import org.cpte.modules.shipping.entity.Task;
import org.cpte.modules.shipping.mapper.TaskMapper;
import org.cpte.modules.shipping.service.IPickDetailService;
import org.cpte.modules.shipping.service.ITaskService;
import org.cpte.modules.shipping.vo.TaskGroupKey;
import org.cpte.modules.utils.BatchUtil;
@ -35,9 +42,20 @@ import java.util.stream.Collectors;
@Service
@Slf4j
public class TaskServiceImpl extends ServiceImpl<TaskMapper, Task> implements ITaskService {
@Autowired
private AgvTaskMapper agvTaskMapper;
@Autowired
private IInventoryService iInventoryService;
private IPointService pointService;
@Autowired
private IPickDetailService pickDetailService;
@Autowired
private IInventoryService inventoryService;
@Autowired
private IInventoryLogService inventoryLogService;
@Autowired
private IAgvTaskService agvTaskService;
@ -97,8 +115,8 @@ public class TaskServiceImpl extends ServiceImpl<TaskMapper, Task> implements IT
.itemCode(item.getItemCode())
.fromPointId(fromPoint.getId())
.fromPointCode(fromPoint.getPointCode())
.toPointId(toPoint.getId())
.toPointCode(toPoint.getPointCode())
.toPointId(toPoint == null ? null : toPoint.getId())
.toPointCode(toPoint == null ? null : toPoint.getPointCode())
.stockId(stock.getId())
.stockCode(stock.getStockCode())
.pickId(pickId)
@ -119,14 +137,14 @@ public class TaskServiceImpl extends ServiceImpl<TaskMapper, Task> implements IT
@Override
public void generateAgvTask() {
List<Task> taskList = this.baseMapper.queryUnallocatedTask();
//未下发的任务
List<Task> taskList = this.baseMapper.queryUnIssuedTask();
if (CollectionUtils.isEmpty(taskList)) {
return;
}
//1.获取库存
List<Long> inventoryIds = taskList.stream().map(Task::getInventoryId).distinct().toList();
Map<Long, Inventory> inventoryMap = iInventoryService.queryByInventoryIdsToMap(inventoryIds);
Map<Long, Inventory> inventoryMap = inventoryService.queryByInventoryIdsToMap(inventoryIds);
//2.根据stockCode、fromPointCode、toPointCode 分组
Map<TaskGroupKey, List<Task>> taskGroupMap = taskList.stream()
@ -195,4 +213,190 @@ public class TaskServiceImpl extends ServiceImpl<TaskMapper, Task> implements IT
return this.baseMapper.queryTaskByMainId(id);
}
@Override
@Transactional(rollbackFor = Exception.class)
public void allocationStation() {
//未分配工作站的任务
List<Task> taskList = this.baseMapper.queryUnallocatedTask();
if (CollectionUtils.isEmpty(taskList)) {
log.info("没有待分配的任务");
return;
}
//目前是四个工作站
List<Point> outPoints = pointService.queryPoints(null, null, AreaTypeEnum.CK_DOCK.getValue());
if (CollectionUtils.isEmpty(outPoints)) {
log.info("没有出库工作站");
return;
}
//当前所有工作站执行中的任务
Map<String, Integer> pointTaskCountMap = queryPointTaskCount();
//获取所有起点库位
List<Long> fromPointIds = taskList.stream().map(Task::getFromPointId).distinct().toList();
Map<Long, Point> fromPointMap = pointService.queryByPointIdsToMap(fromPointIds);
//获取所有库存
List<Long> inventoryIds = taskList.stream().map(Task::getInventoryId).distinct().toList();
Map<Long, Inventory> inventoryMap = inventoryService.queryByInventoryIdsToMap(inventoryIds);
//获取所有出库单
List<Long> pickId = taskList.stream().map(Task::getPickId).distinct().toList();
Map<Long, Pick> pickMap = pickDetailService.queryByPickIdsToMap(pickId);
//获取所有出库单明细
List<Long> pickDetailId = taskList.stream().map(Task::getPickDetailId).distinct().toList();
Map<Long, PickDetail> pickDetailMap = pickDetailService.queryByPickDetailIdsToMap(pickDetailId);
for (Task task : taskList) {
//起点
Point fromPoint = fromPointMap.get(task.getFromPointId());
//选择最优且任务数最少的工作站
Point bestOutPoint = selectBestAvailableOutboundPoint(fromPoint, outPoints, pointTaskCountMap);
task.setToPointId(bestOutPoint.getId());
task.setToPointCode(bestOutPoint.getPointCode());
//分配日志
Inventory inventory = inventoryMap.get(task.getInventoryId());
Pick pick = pickMap.get(task.getPickId());
PickDetail pickDetail = pickDetailMap.get(task.getPickDetailId());
if (inventory != null && pick != null && pickDetail != null) {
inventoryLogService.addAllocInventoryLog(inventory, bestOutPoint.getId(),
task.getPlanQty(), pick.getOrderNo(), pickDetail.getId(), pickDetail.getDescription());
}
//更新该工作站任务计数
pointTaskCountMap.put(bestOutPoint.getPointCode(), pointTaskCountMap.getOrDefault(bestOutPoint.getPointCode(), 0) + 1);
}
//批量更新任务
if (CollectionUtils.isNotEmpty(taskList)) {
this.baseMapper.updateById(taskList);
}
}
/**
*
*
* @return Map<Point, Integer>
*/
private Map<String, Integer> queryPointTaskCount() {
List<Map<String, Integer>> result = agvTaskMapper.pointTaskCountMap();
//遍历result
Map<String, Integer> pointTaskCountMap = new HashMap<>();
for (Map<String, Integer> map : result) {
// 将每个Map中的键值对添加到总Map中
pointTaskCountMap.putAll(map);
}
return pointTaskCountMap;
}
/**
* 3
*/
private Point selectBestAvailableOutboundPoint(Point fromPoint, List<Point> outPoints, Map<String, Integer> pointTaskCountMap) {
// 首先尝试找到任务数小于3的最优工作站
List<Point> availablePoints = outPoints.stream()
.filter(point -> pointTaskCountMap.getOrDefault(point.getPointCode(), 0) < 3)
.collect(Collectors.toList());
if (!availablePoints.isEmpty()) {
// 在任务数小于3的工作站中选择最优的
return getBestOutboundPoint(fromPoint, availablePoints);
} else {
// 所有工作站任务数都≥3选择任务数最少的最优工作站
return findLeastBusyPoint(outPoints, pointTaskCountMap);
}
}
/**
* @param currPoint
* @param outPoints
* @return
*/
private Point getBestOutboundPoint(Point currPoint, List<Point> outPoints) {
//提升机第一层的坐标
Station oneHoist = new Station(4160, 12080);
//提升机第二层的坐标
Station twoHoist = new Station(94160, 12080);
// 获取当前库位所在的层数
int currentLayer = Integer.parseInt(currPoint.getLayerNum());
// 用于存储最佳出库口
Point bestOutPoint = null;
//最小总距离
double minTotalDistance = Double.MAX_VALUE;
// 遍历所有出库口,计算每个出库口的总距离
for (Point outPoint : outPoints) {
double totalDistance = 0;
if (CommonStatusEnum.ONE.getValue().equals(currentLayer)) {
// 如果是第一层:当前库位到第一层提升机的距离 + 第一层提升机到出库口的距离
double currToHoist = calculateManhattanDistance(currPoint, oneHoist);
double hoistToOut = calculateManhattanDistance(oneHoist, outPoint);
totalDistance = currToHoist + hoistToOut;
} else if (CommonStatusEnum.TWO.getValue().equals(currentLayer)) {
// 当前库位到第二层提升机的距离
double currToTwoHoist = calculateManhattanDistance(currPoint, twoHoist);
// 第二层提升机到第一层提升机的距离
double twoHoistToOneHoist = calculateManhattanDistance(twoHoist, oneHoist);
// 第一层提升机到出库口的距离
double oneHoistToOut = calculateManhattanDistance(oneHoist, outPoint);
totalDistance = currToTwoHoist + twoHoistToOneHoist + oneHoistToOut;
}
// 如果当前出库口的总距离更小,更新最佳出库口
if (totalDistance < minTotalDistance) {
minTotalDistance = totalDistance;
bestOutPoint = outPoint;
}
}
return bestOutPoint;
}
// 重载方法用于计算Station和Station之间的曼哈顿距离
private double calculateManhattanDistance(Station station, Station station2) {
int dx = Math.abs(station.getPositionX() - station2.getPositionX());
int dy = Math.abs(station.getPositionY() - station2.getPositionY());
return dx + dy; // 曼哈顿距离
}
// 重载方法用于计算Station和Point之间的曼哈顿距离
private double calculateManhattanDistance(Station station, Point point) {
// 假设Station也有getX()和getY()方法
int dx = Math.abs(station.getPositionX() - point.getPositionX());
int dy = Math.abs(station.getPositionY() - point.getPositionY());
return dx + dy; // 曼哈顿距离
}
// 重载方法用于计算Point和Station之间的曼哈顿距离
private double calculateManhattanDistance(Point point, Station station) {
// 假设Station也有getX()和getY()方法
int dx = Math.abs(station.getPositionX() - point.getPositionX());
int dy = Math.abs(station.getPositionY() - point.getPositionY());
return dx + dy; // 曼哈顿距离
}
/**
*
*/
private Point findLeastBusyPoint(List<Point> outPoints, Map<String, Integer> pointTaskCountMap) {
return outPoints.stream()
.min(Comparator.comparingInt(point -> pointTaskCountMap.getOrDefault(point.getPointCode(), 0)))
.orElse(outPoints.get(0));
}
}

View File

@ -386,7 +386,7 @@ public class AllocateProcessor {
// 获取需要移位的库位
getMovePoints(inventoryScore, movePoints);
// 记录分配日志
inventoryLogService.addAllocInventoryLog(inventory, inventoryScore.getOutPoint().getId(), allocateQty, pick.getOrderNo(), pickDetail.getId(), pickDetail.getDescription());
//inventoryLogService.addAllocInventoryLog(inventory, inventoryScore.getOutPoint().getId(), allocateQty, pick.getOrderNo(), pickDetail.getId(), pickDetail.getDescription());
// 更新剩余未分配数量
remainingQty = BigDecimalUtil.subtract(remainingQty, allocateQty, 0);
@ -413,13 +413,13 @@ public class AllocateProcessor {
Map<Long, Point> pointMap = pointService.queryByPointIdsToMap(pointIds);
//获取出库口的库位
List<Point> outPoints = pointService.queryPoints(null, null, AreaTypeEnum.CK_DOCK.getValue());
// List<Point> outPoints = pointService.queryPoints(null, null, AreaTypeEnum.CK_DOCK.getValue());
//获取优化后的库存
return matchedInventories.stream()
.map(inventory -> {
Point currPoint = pointMap.get(inventory.getPointId());
return calculateMoveCount(inventory, currPoint, outPoints);
return calculateMoveCount(inventory, currPoint);
})
//按分数倒序排序、移动次数升序排序
.sorted(Comparator.comparing(InventoryScore::getScore).reversed()
@ -435,15 +435,17 @@ public class AllocateProcessor {
* @param currPoint
* @return
*/
private InventoryScore calculateMoveCount(Inventory inventory, Point currPoint, List<Point> outPoints) {
private InventoryScore calculateMoveCount(Inventory inventory, Point currPoint) {
// 位移分数
double moveScore;
//移位库位
List<Point> movePoints;
// 计算距离分数权重30%
Point bestPoint = getBestOutboundPoint(currPoint, outPoints);
double distanceScore = calculateClusterDistanceCost(currPoint, bestPoint) * 0.3;
//Point bestPoint = getBestOutboundPoint(currPoint, outPoints);
//double distanceScore = calculateClusterDistanceCost(currPoint, bestPoint) * 0.3;
double distanceScore =0;
//当前巷道的库位数
List<Point> points = pointMapper.findByColAndLayer(currPoint.getColNum(), currPoint.getLayerNum());
@ -473,7 +475,7 @@ public class AllocateProcessor {
log.info("【{}】库位距离评分: {}-移位评分: {}-总得分: {}-移位次数: {}",
currPoint.getPointCode(), distanceScore, moveScore, totalScore, movePoints.size());
return new InventoryScore(inventory, inventory.getStockId(), totalScore, bestPoint, movePoints);
return new InventoryScore(inventory, inventory.getStockId(), totalScore, movePoints);
}
/**
@ -677,12 +679,12 @@ public class AllocateProcessor {
Integer izAll = originalAvailableQty.compareTo(allocateQty) == 0 ? 0 : 1;
// 目标库位
Point toPoint = inventoryScore.getOutPoint();
//Point toPoint = inventoryScore.getOutPoint();
// 构建拣货任务
String taskNo = String.format("%s_%d", pick.getNo(), pickDetail.getLineNo());
Task task = taskService.bulidTask(
taskNo, TaskTypeEnum.PICK.getValue(), item, fromPoint, toPoint,
taskNo, TaskTypeEnum.PICK.getValue(), item, fromPoint, null,
stock, pick.getId(), pickDetail.getId(), inventory.getItemKeyId(), inventory.getId(),
allocateQty, izAll);

View File

@ -17,7 +17,7 @@ public class InventoryScore {
// 分数
private double score;
//最佳出库口
private Point outPoint;
//private Point outPoint;
//移位的库位
private List<Point> movePoints;
}

View File

@ -295,7 +295,7 @@ public class BatchUtil {
ps.setString(4, task.getItemCode());
ps.setLong(5, task.getFromPointId());
ps.setString(6, task.getFromPointCode());
ps.setLong(7, task.getToPointId());
ps.setObject(7, task.getToPointId());
ps.setString(8, task.getToPointCode());
ps.setLong(9, task.getStockId());
ps.setString(10, task.getStockCode());

View File

@ -280,7 +280,6 @@ jeecg:
#分布式锁配置
redisson:
address: 47.117.45.79:6379
#address: 10.254.27.192:6379
password: cpte@123
type: STANDALONE
enabled: true