no message
parent
5cdc1e3021
commit
126414e875
|
|
@ -47,6 +47,6 @@ public interface PointMapper extends BaseMapper<Point> {
|
|||
@Select("SELECT COUNT(id) FROM base_point WHERE col_num = #{colNum} AND layer_num = #{layerNum} AND status = 1")
|
||||
int countOccupiedInSameColumn(@Param("colNum") String colNum, @Param("layerNum") String layerNum);
|
||||
|
||||
|
||||
|
||||
@Select("SELECT * FROM base_point WHERE col_num = #{colNum} AND layer_num = #{layerNum} ORDER BY row_num ASC")
|
||||
List<Point> findByColAndLayer(@Param("colNum") String colNum, @Param("layerNum") String layerNum);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -22,18 +22,24 @@
|
|||
JOIN base_area ba ON bp1.area_id = ba.id
|
||||
JOIN base_point bp2 ON bp1.col_num = bp2.col_num
|
||||
JOIN data_inventory inv ON bp2.id = inv.point_id
|
||||
<where>
|
||||
AND inv.item_id = #{itemId}
|
||||
<if test="propC1 != null and propC1 != ''">
|
||||
WHERE inv.item_id = #{itemId}
|
||||
AND bp1.status = 0
|
||||
AND ba.area_code = #{areaCode}
|
||||
<choose>
|
||||
<when test="propC1 != null and propC1 != ''">
|
||||
AND inv.prop_c1 = #{propC1}
|
||||
</if>
|
||||
<if test="whCode != null and whCode != ''">
|
||||
</when>
|
||||
<otherwise>
|
||||
AND (inv.prop_c1 IS NULL OR inv.prop_c1 = '')
|
||||
</otherwise>
|
||||
</choose>
|
||||
<choose>
|
||||
<when test="whCode != null and whCode != ''">
|
||||
AND inv.wh_code = #{whCode}
|
||||
</if>
|
||||
<if test="areaCode != null and areaCode != ''">
|
||||
AND ba.area_code = #{areaCode}
|
||||
</if>
|
||||
AND bp1.status = 0
|
||||
</where>
|
||||
</when>
|
||||
<otherwise>
|
||||
AND (inv.wh_code IS NULL OR inv.wh_code = '')
|
||||
</otherwise>
|
||||
</choose>
|
||||
</select>
|
||||
</mapper>
|
||||
|
|
@ -80,5 +80,21 @@ public interface IPointService extends IService<Point> {
|
|||
*/
|
||||
String getElevatorPoint(String pointCode, String key);
|
||||
|
||||
Point queryToPoint(String pointCode, Integer status, String areaCode);
|
||||
/**
|
||||
* 通过巷道编码、层数查询库位信息
|
||||
*
|
||||
* @param colNum 巷道编码
|
||||
* @return layerNum 层数
|
||||
*/
|
||||
List<Point> findByColAndLayer(String colNum, String layerNum);
|
||||
|
||||
/**
|
||||
* 查询库位信息
|
||||
*
|
||||
* @param pointCode 库位编码
|
||||
* @param status 状态
|
||||
* @param areaCode 库区编码
|
||||
* @return List<Point>
|
||||
*/
|
||||
List<Point> queryPoints(String pointCode, Integer status, String areaCode);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -144,12 +144,13 @@ public class PointServiceImpl extends ServiceImpl<PointMapper, Point> implements
|
|||
}
|
||||
|
||||
@Override
|
||||
public Point queryToPoint(String pointCode, Integer status, String areaCode) {
|
||||
Point dstPoint = null;
|
||||
List<Point> dstPointList = pointMapper.queryPoints(pointCode, status, areaCode);
|
||||
if (dstPointList.isEmpty()) {
|
||||
throw new RuntimeException("【" + AreaTypeEnum.CPCCQ.getDesc() + "】无空闲库位");
|
||||
}
|
||||
return dstPoint = dstPointList.get(0);
|
||||
public List<Point> findByColAndLayer(String colNum, String layerNum) {
|
||||
return pointMapper.findByColAndLayer(colNum, layerNum);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Point> queryPoints(String pointCode, Integer status, String areaCode) {
|
||||
return pointMapper.queryPoints(pointCode, status, areaCode);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,9 +15,9 @@ public enum AreaTypeEnum {
|
|||
|
||||
MJCCQ("MJCCQ", "模具存储区"),
|
||||
|
||||
RK_DOCK("RK_DOCK", "入库输送线接驳口"),
|
||||
RK_DOCK("RK_DOCK", "入库工作站"),
|
||||
|
||||
CK_DOCK("CK_DOCK", "出库输送线接驳口"),
|
||||
CK_DOCK("CK_DOCK", "出库工作站"),
|
||||
;
|
||||
/**
|
||||
* 值
|
||||
|
|
|
|||
|
|
@ -7,12 +7,10 @@ import lombok.Data;
|
|||
@Data
|
||||
public class ScanTrayRequest {
|
||||
//托盘码
|
||||
@NotBlank(message = "托盘码不能为空")
|
||||
@JsonProperty("stockCode")
|
||||
private String stockCode;
|
||||
|
||||
//工作站
|
||||
@NotBlank(message = "工作站不能为空")
|
||||
@JsonProperty("station")
|
||||
private String station;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -65,9 +65,21 @@ public class IConveyorLineServiceImpl implements IConveyorLineService {
|
|||
@Autowired
|
||||
private IAgvTaskService iAgvTaskService;
|
||||
|
||||
private void validateParams(ScanTrayRequest scanTrayRequest) {
|
||||
if (StringUtils.isBlank(scanTrayRequest.getStockCode())) {
|
||||
throw new RuntimeException("托盘码不能为空");
|
||||
}
|
||||
if (StringUtils.isBlank(scanTrayRequest.getStation())) {
|
||||
throw new RuntimeException("工作站不能为空");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void scanTray(ScanTrayRequest scanTrayRequest) {
|
||||
//验证参数
|
||||
validateParams(scanTrayRequest);
|
||||
|
||||
//工作站
|
||||
Point srcPoint = pointMapper.queryByPointCode(scanTrayRequest.getStation());
|
||||
|
||||
|
|
|
|||
|
|
@ -35,7 +35,7 @@ public interface InventoryMapper extends BaseMapper<Inventory> {
|
|||
* @param whCodeList 外部仓库
|
||||
* @return List<Inventory>
|
||||
*/
|
||||
List<Inventory> queryInventoryWithLock(@Param("itemIds") List<Long> itemIds, @Param("propC1List") List<String> propC1List, @Param("propC3List") List<String> propC3List, @Param("whCodeList") List<String> whCodeList);
|
||||
List<Inventory> queryInventory(@Param("itemIds") List<Long> itemIds, @Param("propC1List") List<String> propC1List, @Param("propC3List") List<String> propC3List, @Param("whCodeList") List<String> whCodeList);
|
||||
|
||||
// 查询相邻库位(同一巷道,深度±3范围内)
|
||||
@Select("SELECT di.* " +
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||
<mapper namespace="org.cpte.modules.inventory.mapper.InventoryMapper">
|
||||
<select id="queryInventoryWithLock" resultType="org.cpte.modules.inventory.entity.Inventory">
|
||||
<select id="queryInventory" resultType="org.cpte.modules.inventory.entity.Inventory">
|
||||
SELECT * FROM data_inventory
|
||||
WHERE status in (1,2)
|
||||
AND quantity > 0
|
||||
|
|
@ -9,25 +9,41 @@
|
|||
<foreach collection="itemIds" item="itemId" open="(" separator="," close=")">
|
||||
#{itemId}
|
||||
</foreach>
|
||||
<if test="propC1List != null and !propC1List.isEmpty()">
|
||||
AND prop_c1 IN
|
||||
<foreach collection="propC1List" item="propC1" open="(" separator="," close=")">
|
||||
#{propC1}
|
||||
</foreach>
|
||||
</if>
|
||||
<if test="propC3List != null and !propC3List.isEmpty()">
|
||||
AND prop_c3 IN
|
||||
<foreach collection="propC3List" item="propC3" open="(" separator="," close=")">
|
||||
#{propC3}
|
||||
</foreach>
|
||||
</if>
|
||||
<if test="whCodeList != null and !whCodeList.isEmpty()">
|
||||
AND wh_code IN
|
||||
<foreach collection="whCodeList" item="whCode" open="(" separator="," close=")">
|
||||
#{whCode}
|
||||
</foreach>
|
||||
</if>
|
||||
<choose>
|
||||
<when test="propC1List != null and !propC1List.isEmpty()">
|
||||
AND prop_c1 IN
|
||||
<foreach collection="propC1List" item="propC1" open="(" separator="," close=")">
|
||||
#{propC1}
|
||||
</foreach>
|
||||
</when>
|
||||
<otherwise>
|
||||
AND (prop_c1 IS NULL OR prop_c1 = '')
|
||||
</otherwise>
|
||||
</choose>
|
||||
|
||||
<choose>
|
||||
<when test="propC3List != null and !propC3List.isEmpty()">
|
||||
AND prop_c3 IN
|
||||
<foreach collection="propC3List" item="propC3" open="(" separator="," close=")">
|
||||
#{propC3}
|
||||
</foreach>
|
||||
</when>
|
||||
<otherwise>
|
||||
AND (prop_c3 IS NULL OR prop_c3 = '')
|
||||
</otherwise>
|
||||
</choose>
|
||||
|
||||
<choose>
|
||||
<when test="whCodeList != null and !whCodeList.isEmpty()">
|
||||
AND wh_code IN
|
||||
<foreach collection="whCodeList" item="whCode" open="(" separator="," close=")">
|
||||
#{whCode}
|
||||
</foreach>
|
||||
</when>
|
||||
<otherwise>
|
||||
AND (wh_code IS NULL OR wh_code = '')
|
||||
</otherwise>
|
||||
</choose>
|
||||
ORDER BY create_time
|
||||
FOR UPDATE
|
||||
</select>
|
||||
</mapper>
|
||||
|
|
@ -49,12 +49,13 @@ public interface IInventoryLogService extends IService<InventoryLog> {
|
|||
* 添加分配库存日志
|
||||
*
|
||||
* @param inventory 库存
|
||||
* @param dstPointId 目标库位
|
||||
* @param AllocatedQty 分配数量
|
||||
* @param businessNo 业务单号
|
||||
* @param businessDetailId 业务明细ID
|
||||
* @param description 描述
|
||||
*/
|
||||
void addAllocInventoryLog(Inventory inventory, BigDecimal AllocatedQty, String businessNo, Long businessDetailId, String description);
|
||||
void addAllocInventoryLog(Inventory inventory, Long dstPointId, BigDecimal AllocatedQty, String businessNo, Long businessDetailId, String description);
|
||||
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -61,10 +61,12 @@ public class InventoryLogServiceImpl extends ServiceImpl<InventoryLogMapper, Inv
|
|||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void addAllocInventoryLog(Inventory inventory, BigDecimal AllocatedQty, String businessNo, Long businessDetailId, String description) {
|
||||
public void addAllocInventoryLog(Inventory inventory,Long dstPointId, BigDecimal AllocatedQty, String businessNo, Long businessDetailId, String description) {
|
||||
InventoryLog inventoryLog = buildInventoryLog(inventory, BigDecimal.ZERO, businessNo, businessDetailId, description);
|
||||
//出库分配
|
||||
inventoryLog.setLogType(InventoryLogEnum.ALLOC.getValue());
|
||||
inventoryLog.setFromPointId(inventory.getPointId());
|
||||
inventoryLog.setToPointId(dstPointId);
|
||||
//实际数量不变
|
||||
inventoryLog.setChangeQty(BigDecimal.ZERO);
|
||||
inventoryLog.setBeforeAllocatedQty(BigDecimalUtil.subtract(inventory.getQueuedQty(), AllocatedQty, 0));
|
||||
|
|
|
|||
|
|
@ -149,7 +149,7 @@ public class ISaiWmsServiceImpl implements ISaiWmsService {
|
|||
Stock stock = iStockService.validateStock(stockCode);
|
||||
|
||||
//获取输送线工作台点位,均衡分配点位任务-轮询方式
|
||||
Point dstPoint = iPointService.getWorkStationPoint(CommonStatusEnum.FREE.getValue(), AreaTypeEnum.RK_DOCK.getValue(), GeneralConstant.RK_DOCK_TASK_INDEX);
|
||||
Point dstPoint = iPointService.getWorkStationPoint(null, AreaTypeEnum.RK_DOCK.getValue(), GeneralConstant.RK_DOCK_TASK_INDEX);
|
||||
|
||||
// 创建入库单和明细
|
||||
Asn createAsn = buildAsn(inboundRequest);
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ import org.cpte.modules.base.service.IItemService;
|
|||
import org.cpte.modules.base.service.IPointService;
|
||||
import org.cpte.modules.base.service.IStockService;
|
||||
import org.cpte.modules.constant.enums.*;
|
||||
import org.cpte.modules.conveyorLine.vo.PointScore;
|
||||
import org.cpte.modules.inventory.entity.Inventory;
|
||||
import org.cpte.modules.inventory.mapper.InventoryMapper;
|
||||
import org.cpte.modules.inventory.service.IInventoryService;
|
||||
|
|
@ -27,6 +28,7 @@ import org.cpte.modules.shipping.mapper.TaskMapper;
|
|||
import org.cpte.modules.shipping.service.IPickService;
|
||||
import org.cpte.modules.shipping.service.ITaskService;
|
||||
import org.cpte.modules.shipping.vo.InventoryGroupKey;
|
||||
import org.cpte.modules.shipping.vo.InventoryScore;
|
||||
import org.cpte.modules.utils.BatchUtil;
|
||||
import org.cpte.modules.utils.BigDecimalUtil;
|
||||
import org.jeecg.common.constant.CommonConstant;
|
||||
|
|
@ -318,7 +320,7 @@ public class PickServiceImpl extends ServiceImpl<PickMapper, Pick> implements IP
|
|||
List<String> whCodeList = pickMap.values().stream().map(Pick::getWhCode).filter(StringUtils::hasText).distinct().toList();
|
||||
|
||||
//查询库存
|
||||
List<Inventory> inventories = inventoryMapper.queryInventoryWithLock(itemIds, propC1List, propC3List, whCodeList);
|
||||
List<Inventory> inventories = inventoryMapper.queryInventory(itemIds, propC1List, propC3List, whCodeList);
|
||||
if (CollectionUtils.isEmpty(inventories)) {
|
||||
String itemCodes = itemMap.values().stream().map(Item::getItemCode).collect(Collectors.joining(","));
|
||||
errorMsgSet.add("【" + itemCodes + "】物料库存不足");
|
||||
|
|
@ -374,14 +376,14 @@ public class PickServiceImpl extends ServiceImpl<PickMapper, Pick> implements IP
|
|||
continue;
|
||||
}
|
||||
|
||||
//获取输送线工作台点位,均衡分配点位任务-轮询方式
|
||||
Point toPoint = iPointService.getWorkStationPoint(CommonStatusEnum.FREE.getValue(), AreaTypeEnum.CK_DOCK.getValue(), GeneralConstant.CK_DOCK_TASK_INDEX);
|
||||
//记录当前容器
|
||||
Long currStockId = 0L;
|
||||
for (Inventory inventory : matchedInventories) {
|
||||
//智能排序,优先分配移位最小的库位
|
||||
List<InventoryScore> scoredInventory = scoreInventories(matchedInventories);
|
||||
|
||||
for (InventoryScore inventoryScore : scoredInventory) {
|
||||
if (unAllocatedQty.compareTo(BigDecimal.ZERO) <= 0) {
|
||||
break;
|
||||
}
|
||||
Inventory inventory = inventoryScore.getInventory();
|
||||
// 库存可用数量
|
||||
BigDecimal availableQty = BigDecimalUtil.subtract(inventory.getQuantity(), inventory.getQueuedQty(), 0);
|
||||
if (availableQty.compareTo(BigDecimal.ZERO) <= 0) {
|
||||
|
|
@ -405,20 +407,26 @@ public class PickServiceImpl extends ServiceImpl<PickMapper, Pick> implements IP
|
|||
Point fromPoint = pointMap.get(inventory.getPointId());
|
||||
//是否整托:0整托、1拆托
|
||||
Integer izAll = availableQty.compareTo(allocateQty) == 0 ? 0 : 1;
|
||||
//判断当前容器是否一致,同一个容器去同一个目标库位
|
||||
if (!currStockId.equals(stock.getId())) {
|
||||
toPoint = iPointService.getWorkStationPoint(CommonStatusEnum.FREE.getValue(), AreaTypeEnum.CK_DOCK.getValue(), GeneralConstant.CK_DOCK_TASK_INDEX);
|
||||
}
|
||||
//目标库位
|
||||
Point toPoint = inventoryScore.getOutPoint();
|
||||
//构建拣货任务存入集合批量新增
|
||||
Task task = iTaskService.bulidTask(pick.getNo() + "_" + pickDetail.getLineNo(), TaskTypeEnum.PICK.getValue(), item, fromPoint, toPoint, stock, pick.getId(), pickDetail.getId(), inventory.getId(), allocateQty, izAll);
|
||||
createToTask.add(task);
|
||||
log.info("生成拣货任务:{}- 容器:{} - 库位:{} - 类型:{}- 分配数量:{}", task.getTaskNo(), stock.getStockCode(), fromPoint.getPointCode(), izAll, allocateQty);
|
||||
|
||||
//移位任务
|
||||
if (CollectionUtils.isNotEmpty(inventoryScore.getMovePoints())) {
|
||||
for (Point movePoint : inventoryScore.getMovePoints()) {
|
||||
log.info("生成移位任务:原库位:{}", movePoint.getPointCode());
|
||||
}
|
||||
} else {
|
||||
log.info("无移位任务");
|
||||
}
|
||||
|
||||
//分配库存日志
|
||||
iInventoryLogService.addAllocInventoryLog(inventory, allocateQty, pick.getOrderNo(), pickDetail.getId(), pickDetail.getDescription());
|
||||
iInventoryLogService.addAllocInventoryLog(inventory, toPoint.getId(), allocateQty, pick.getOrderNo(), pickDetail.getId(), pickDetail.getDescription());
|
||||
//更新未分配数量
|
||||
unAllocatedQty = BigDecimalUtil.subtract(unAllocatedQty, allocateQty, 0);
|
||||
//更新当前容器
|
||||
currStockId = stock.getId();
|
||||
}
|
||||
//分配后仍有缺货,记录错误
|
||||
if (unAllocatedQty.compareTo(BigDecimal.ZERO) > 0) {
|
||||
|
|
@ -453,6 +461,145 @@ public class PickServiceImpl extends ServiceImpl<PickMapper, Pick> implements IP
|
|||
return new ArrayList<>(errorMsgSet);
|
||||
}
|
||||
|
||||
/**
|
||||
* 计算库存得分
|
||||
*
|
||||
* @param matchedInventories 库存集合
|
||||
* @return List<InventoryScore>
|
||||
*/
|
||||
private List<InventoryScore> scoreInventories(List<Inventory> matchedInventories) {
|
||||
// 批量查询库位
|
||||
List<Long> pointIds = matchedInventories.stream()
|
||||
.map(Inventory::getPointId)
|
||||
.toList();
|
||||
Map<Long, Point> pointMap = iPointService.queryByPointIdsToMap(pointIds);
|
||||
|
||||
// 按巷道和层分组
|
||||
Map<String, List<Point>> colLayerPointsMap = new HashMap<>();
|
||||
|
||||
for (Point point : pointMap.values()) {
|
||||
String key = point.getColNum() + "-" + point.getLayerNum();
|
||||
if (colLayerPointsMap.containsKey(key)) {
|
||||
continue;
|
||||
}
|
||||
List<Point> points = iPointService.findByColAndLayer(point.getColNum(), point.getLayerNum());
|
||||
colLayerPointsMap.put(key, points);
|
||||
}
|
||||
|
||||
//获取所以出库口的库位
|
||||
List<Point> outPoints = iPointService.queryPoints(null, null, AreaTypeEnum.CK_DOCK.getValue());
|
||||
|
||||
//获取优化后的库存
|
||||
return matchedInventories.stream()
|
||||
.map(inventory -> {
|
||||
Point currPoint = pointMap.get(inventory.getPointId());
|
||||
String key = currPoint.getColNum() + "-" + currPoint.getLayerNum();
|
||||
List<Point> points = colLayerPointsMap.get(key);
|
||||
return calculateMoveCount(inventory, currPoint, points, outPoints);
|
||||
})
|
||||
.sorted(Comparator.comparing(InventoryScore::getScore).reversed())
|
||||
.toList();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 计算位移次数核心算法
|
||||
*
|
||||
* @param inventory 库存
|
||||
* @param currPoint 当前库位
|
||||
* @param points 当前库位巷道的库位集合
|
||||
* @return 库位位移次数
|
||||
*/
|
||||
private InventoryScore calculateMoveCount(Inventory inventory, Point currPoint, List<Point> points, List<Point> outPoints) {
|
||||
double totalScore = 0.0;
|
||||
|
||||
// 计算距离分数(权重30%)
|
||||
Point bestPoint = getBestOutboundPoint(currPoint, outPoints);
|
||||
double distanceScore = calculateClusterDistanceCost(currPoint, bestPoint);
|
||||
totalScore += distanceScore * 0.3;
|
||||
|
||||
// 目标库位的深度位转换为索引
|
||||
int targetIndex = Integer.parseInt(currPoint.getRowNum()) - 1;
|
||||
|
||||
//双通道
|
||||
if (currPoint.getIzDoubleLane().equals(1)) {
|
||||
// 计算左侧占用数
|
||||
int leftOccupied = 0;
|
||||
List<Point> leftPoints = new ArrayList<>();
|
||||
for (int i = 0; i < targetIndex; i++) {
|
||||
Point point = points.get(i);
|
||||
if (point != null && point.getStatus().equals(CommonStatusEnum.USED.getValue())) {
|
||||
leftOccupied++;
|
||||
leftPoints.add(point);
|
||||
}
|
||||
}
|
||||
|
||||
// 计算右侧占用数
|
||||
int rightOccupied = 0;
|
||||
List<Point> rightPoints = new ArrayList<>();
|
||||
for (int i = targetIndex + 1; i < points.size(); i++) {
|
||||
Point point = points.get(i);
|
||||
if (point != null && point.getStatus().equals(CommonStatusEnum.USED.getValue())) {
|
||||
rightOccupied++;
|
||||
rightPoints.add(point);
|
||||
}
|
||||
}
|
||||
//取两个集合中,元素最少的那个集合
|
||||
List<Point> movePoints = leftOccupied < rightOccupied ? leftPoints : rightPoints;
|
||||
// 取最小值,移位越小分数越高
|
||||
int minOccupied = Math.min(leftOccupied, rightOccupied);
|
||||
if (minOccupied == 0) {
|
||||
minOccupied = 1; // 设置默认值防止除以0
|
||||
}
|
||||
totalScore += 100.0 / minOccupied * 0.7;
|
||||
return new InventoryScore(inventory, totalScore, bestPoint, movePoints);
|
||||
} else {
|
||||
// 单通道,计算目标位置左侧的占用数
|
||||
int leftOccupied = 0;
|
||||
List<Point> movePoints = new ArrayList<>();
|
||||
for (int i = 0; i < targetIndex; i++) {
|
||||
Point point = points.get(i);
|
||||
if (point != null && point.getStatus().equals(CommonStatusEnum.USED.getValue())) {
|
||||
leftOccupied++;
|
||||
movePoints.add(point);
|
||||
}
|
||||
}
|
||||
if (leftOccupied == 0) {
|
||||
leftOccupied = 1;
|
||||
}
|
||||
totalScore += 100.0 / leftOccupied * 0.7;
|
||||
return new InventoryScore(inventory, totalScore, bestPoint, movePoints);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param currPoint 当前库位
|
||||
* @param outPoints 出库口集合
|
||||
* @return 最佳出库口
|
||||
*/
|
||||
private Point getBestOutboundPoint(Point currPoint, List<Point> outPoints) {
|
||||
//获取距离最近的出库口
|
||||
return outPoints.stream()
|
||||
.min(Comparator.comparingDouble(point ->
|
||||
Math.abs(currPoint.getPositionX() - point.getPositionX()) +
|
||||
Math.abs(currPoint.getPositionY() - point.getPositionY())))
|
||||
.orElse(null);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 计算距离评分
|
||||
* 基于出库口位置和库位坐标计算最短路径距离
|
||||
*/
|
||||
private double calculateClusterDistanceCost(Point point, Point station) {
|
||||
// 计算曼哈顿距离
|
||||
double distance = Math.abs(point.getPositionX() - station.getPositionX()) + Math.abs(point.getPositionY() - station.getPositionY());
|
||||
|
||||
// 距离越小分数越高
|
||||
return Math.max(0, 100 - (distance / 100.0));
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public List<String> cancelAllocate(List<Long> pickIds) {
|
||||
|
|
@ -528,7 +675,7 @@ public class PickServiceImpl extends ServiceImpl<PickMapper, Pick> implements IP
|
|||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void pickTask(List<Task> tasks,Point endPoint) {
|
||||
public void pickTask(List<Task> tasks, Point endPoint) {
|
||||
if (CollectionUtils.isEmpty(tasks)) {
|
||||
throw new RuntimeException("无拣货任务");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,21 @@
|
|||
package org.cpte.modules.shipping.vo;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import org.cpte.modules.base.entity.Point;
|
||||
import org.cpte.modules.inventory.entity.Inventory;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Data
|
||||
@AllArgsConstructor
|
||||
public class InventoryScore {
|
||||
// 库存
|
||||
private Inventory inventory;
|
||||
// 分数
|
||||
private double score;
|
||||
//最佳出库口
|
||||
private Point outPoint;
|
||||
//移位的库位
|
||||
private List<Point> movePoints;
|
||||
}
|
||||
|
|
@ -178,7 +178,7 @@ mybatis-plus:
|
|||
table-underline: true
|
||||
configuration:
|
||||
# # 这个配置会将执行的sql打印出来,在开发或测试的时候可以用
|
||||
#log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
|
||||
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
|
||||
# 返回类型为Map,显示null对应的字段
|
||||
call-setters-on-nulls: true
|
||||
#jeecg专用配置
|
||||
|
|
|
|||
Loading…
Reference in New Issue