From dd82132205ac32a21899a868c49c8167c5658ad7 Mon Sep 17 00:00:00 2001 From: zgw <13623675548@163.com> Date: Thu, 16 Jul 2026 10:35:03 +0800 Subject: [PATCH] feat: add KPI dense lane relocation --- .../ruoyi/kpi/controller/KpiController.java | 23 ++ .../com/ruoyi/kpi/service/KpiService.java | 9 + .../kpi/service/impl/KpiServiceImpl.java | 61 ++++ .../out/dense/domain/DenseLaneOption.java | 35 ++ .../out/dense/domain/DenseLanePosition.java | 5 + .../out/dense/mapper/DenseLaneMapper.java | 4 + .../resources/mapper/out/DenseLaneMapper.xml | 47 +++ .../mapper/out/RelocationJobMapper.xml | 11 +- .../impl/KpiDenseRelocationServiceTest.java | 109 +++++++ ruoyi-ui/src/api/kpi/kpi.js | 33 ++ ruoyi-ui/src/views/kpi/plan/index.vue | 298 +++++++++++++++++- 11 files changed, 633 insertions(+), 2 deletions(-) create mode 100644 ruoyi-admin/src/main/java/com/ruoyi/out/dense/domain/DenseLaneOption.java create mode 100644 ruoyi-admin/src/test/java/com/ruoyi/kpi/service/impl/KpiDenseRelocationServiceTest.java diff --git a/ruoyi-admin/src/main/java/com/ruoyi/kpi/controller/KpiController.java b/ruoyi-admin/src/main/java/com/ruoyi/kpi/controller/KpiController.java index cbc0315..e6f5a41 100644 --- a/ruoyi-admin/src/main/java/com/ruoyi/kpi/controller/KpiController.java +++ b/ruoyi-admin/src/main/java/com/ruoyi/kpi/controller/KpiController.java @@ -10,6 +10,8 @@ import com.ruoyi.kpi.service.KpiService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; @@ -63,6 +65,27 @@ public class KpiController extends BaseController return AjaxResult.success(kpiService.getDenseCargoSpacePlanData(warehouseId)); } + @GetMapping("/denseRelocation/options") + @PreAuthorize("@ss.hasPermi('kpi:cargo:space:plan')") + public AjaxResult denseRelocationOptions( + com.ruoyi.out.relocation.domain.RelocationGenerateRequest request) { + return AjaxResult.success(kpiService.getDenseRelocationOptions(request)); + } + + @PostMapping("/denseRelocation/preview") + @PreAuthorize("@ss.hasPermi('kpi:cargo:space:plan')") + public AjaxResult previewDenseRelocation( + @RequestBody com.ruoyi.out.relocation.domain.RelocationGenerateRequest request) { + return AjaxResult.success(kpiService.previewDenseRelocation(request)); + } + + @PostMapping("/denseRelocation/generate") + @PreAuthorize("@ss.hasPermi('kpi:cargo:space:plan')") + public AjaxResult generateDenseRelocation( + @RequestBody com.ruoyi.out.relocation.domain.RelocationGenerateRequest request) { + return AjaxResult.success(kpiService.generateDenseRelocation(request)); + } + /** * 货位平面图-货位详情 */ diff --git a/ruoyi-admin/src/main/java/com/ruoyi/kpi/service/KpiService.java b/ruoyi-admin/src/main/java/com/ruoyi/kpi/service/KpiService.java index 952adcf..ee75412 100644 --- a/ruoyi-admin/src/main/java/com/ruoyi/kpi/service/KpiService.java +++ b/ruoyi-admin/src/main/java/com/ruoyi/kpi/service/KpiService.java @@ -63,4 +63,13 @@ public interface KpiService * @return 包含 msg 的Map */ Map getCargoSpaceMag(String warehouseId, String thePlatoon, String theColumn, String theFloor); + + Map getDenseRelocationOptions( + com.ruoyi.out.relocation.domain.RelocationGenerateRequest request); + + com.ruoyi.out.relocation.domain.RelocationPreview previewDenseRelocation( + com.ruoyi.out.relocation.domain.RelocationGenerateRequest request); + + List generateDenseRelocation( + com.ruoyi.out.relocation.domain.RelocationGenerateRequest request); } diff --git a/ruoyi-admin/src/main/java/com/ruoyi/kpi/service/impl/KpiServiceImpl.java b/ruoyi-admin/src/main/java/com/ruoyi/kpi/service/impl/KpiServiceImpl.java index 706d20d..a6e6740 100644 --- a/ruoyi-admin/src/main/java/com/ruoyi/kpi/service/impl/KpiServiceImpl.java +++ b/ruoyi-admin/src/main/java/com/ruoyi/kpi/service/impl/KpiServiceImpl.java @@ -14,6 +14,11 @@ import com.ruoyi.in.job.mapper.MydoJobMapper; import com.ruoyi.kpi.domain.*; import com.ruoyi.kpi.mapper.KpiMapper; import com.ruoyi.kpi.service.KpiService; +import com.ruoyi.out.dense.domain.DenseLaneOption; +import com.ruoyi.out.dense.mapper.DenseLaneMapper; +import com.ruoyi.out.relocation.domain.RelocationGenerateRequest; +import com.ruoyi.out.relocation.domain.RelocationPreview; +import com.ruoyi.out.relocation.service.IRelocationJobService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; @@ -43,6 +48,12 @@ public class KpiServiceImpl implements KpiService { @Autowired private MydoJobMapper mydoJobMapper; + @Autowired + private DenseLaneMapper denseLaneMapper; + + @Autowired + private IRelocationJobService relocationJobService; + private static final ObjectMapper objectMapper = new ObjectMapper(); private static final String UNASSIGNED_ROADWAY = "未分配"; @@ -420,4 +431,54 @@ public class KpiServiceImpl implements KpiService { result.put("msg", msg.toString()); return result; } + + @Override + public Map getDenseRelocationOptions(RelocationGenerateRequest request) + { + validateDenseRelocationBase(request); + List options = denseLaneMapper.selectLaneOptions( + request.getWarehouseId(), request.getTheFloor()); + if (options == null) { + options = Collections.emptyList(); + } + int requiredCapacity = request.getTrayCount() == null || request.getTrayCount() <= 0 + ? 1 : request.getTrayCount(); + List sourceLanes = options.stream() + .filter(item -> item.getFullTrayCount() != null && item.getFullTrayCount() > 0) + .collect(java.util.stream.Collectors.toList()); + List targetLanes = options.stream() + .filter(item -> !StringUtils.hasText(request.getSourceGroupCoding()) + || !request.getSourceGroupCoding().equals(item.getGroupCoding())) + .filter(item -> item.getEmptyLocationCount() != null + && item.getEmptyLocationCount() >= requiredCapacity) + .collect(java.util.stream.Collectors.toList()); + Map result = new LinkedHashMap<>(); + result.put("sourceLanes", sourceLanes); + result.put("targetLanes", targetLanes); + return result; + } + + @Override + public RelocationPreview previewDenseRelocation(RelocationGenerateRequest request) + { + validateDenseRelocationBase(request); + return relocationJobService.preview(request); + } + + @Override + public List generateDenseRelocation(RelocationGenerateRequest request) + { + validateDenseRelocationBase(request); + return relocationJobService.generate(request); + } + + private void validateDenseRelocationBase(RelocationGenerateRequest request) + { + if (request == null || !"03".equals(request.getWarehouseId())) { + throw new RuntimeException("指定移库仅支持03仓密集库"); + } + if (request.getTheFloor() == null) { + throw new RuntimeException("指定移库必须选择当前层"); + } + } } diff --git a/ruoyi-admin/src/main/java/com/ruoyi/out/dense/domain/DenseLaneOption.java b/ruoyi-admin/src/main/java/com/ruoyi/out/dense/domain/DenseLaneOption.java new file mode 100644 index 0000000..2f2f0c6 --- /dev/null +++ b/ruoyi-admin/src/main/java/com/ruoyi/out/dense/domain/DenseLaneOption.java @@ -0,0 +1,35 @@ +package com.ruoyi.out.dense.domain; + +import java.math.BigDecimal; + +/** + * 密集库通道移库选项。 + */ +public class DenseLaneOption +{ + private String groupCoding; + private String cargoArea; + private Long thePlatoon; + private Long theFloor; + private String directionType; + private Integer fullTrayCount; + private Integer emptyLocationCount; + private BigDecimal totalQuantity; + + public String getGroupCoding() { return groupCoding; } + public void setGroupCoding(String groupCoding) { this.groupCoding = groupCoding; } + public String getCargoArea() { return cargoArea; } + public void setCargoArea(String cargoArea) { this.cargoArea = cargoArea; } + public Long getThePlatoon() { return thePlatoon; } + public void setThePlatoon(Long thePlatoon) { this.thePlatoon = thePlatoon; } + public Long getTheFloor() { return theFloor; } + public void setTheFloor(Long theFloor) { this.theFloor = theFloor; } + public String getDirectionType() { return directionType; } + public void setDirectionType(String directionType) { this.directionType = directionType; } + public Integer getFullTrayCount() { return fullTrayCount; } + public void setFullTrayCount(Integer fullTrayCount) { this.fullTrayCount = fullTrayCount; } + public Integer getEmptyLocationCount() { return emptyLocationCount; } + public void setEmptyLocationCount(Integer emptyLocationCount) { this.emptyLocationCount = emptyLocationCount; } + public BigDecimal getTotalQuantity() { return totalQuantity; } + public void setTotalQuantity(BigDecimal totalQuantity) { this.totalQuantity = totalQuantity; } +} diff --git a/ruoyi-admin/src/main/java/com/ruoyi/out/dense/domain/DenseLanePosition.java b/ruoyi-admin/src/main/java/com/ruoyi/out/dense/domain/DenseLanePosition.java index 604d948..f6a6a27 100644 --- a/ruoyi-admin/src/main/java/com/ruoyi/out/dense/domain/DenseLanePosition.java +++ b/ruoyi-admin/src/main/java/com/ruoyi/out/dense/domain/DenseLanePosition.java @@ -1,5 +1,7 @@ package com.ruoyi.out.dense.domain; +import java.math.BigDecimal; + /** * 密集库通道货位及其几何信息。 */ @@ -19,6 +21,7 @@ public class DenseLanePosition private String directionType; private Long minColumn; private Long maxColumn; + private BigDecimal stockQuantity; public String getCargoSpaceId() { return cargoSpaceId; } public void setCargoSpaceId(String cargoSpaceId) { this.cargoSpaceId = cargoSpaceId; } @@ -48,4 +51,6 @@ public class DenseLanePosition public void setMinColumn(Long minColumn) { this.minColumn = minColumn; } public Long getMaxColumn() { return maxColumn; } public void setMaxColumn(Long maxColumn) { this.maxColumn = maxColumn; } + public BigDecimal getStockQuantity() { return stockQuantity; } + public void setStockQuantity(BigDecimal stockQuantity) { this.stockQuantity = stockQuantity; } } diff --git a/ruoyi-admin/src/main/java/com/ruoyi/out/dense/mapper/DenseLaneMapper.java b/ruoyi-admin/src/main/java/com/ruoyi/out/dense/mapper/DenseLaneMapper.java index 8164f71..6b2a6c9 100644 --- a/ruoyi-admin/src/main/java/com/ruoyi/out/dense/mapper/DenseLaneMapper.java +++ b/ruoyi-admin/src/main/java/com/ruoyi/out/dense/mapper/DenseLaneMapper.java @@ -3,6 +3,7 @@ package com.ruoyi.out.dense.mapper; import java.util.List; import com.ruoyi.bas.cargospace.domain.BasCargoSpace; import com.ruoyi.out.dense.domain.DenseLanePosition; +import com.ruoyi.out.dense.domain.DenseLaneOption; import com.ruoyi.out.dense.domain.RelocationTargetQuery; import org.apache.ibatis.annotations.Param; @@ -20,4 +21,7 @@ public interface DenseLaneMapper List selectBlockersForUpdate(@Param("cargoSpaceId") String cargoSpaceId); BasCargoSpace selectRelocationTargetForUpdate(RelocationTargetQuery query); + + List selectLaneOptions(@Param("warehouseId") String warehouseId, + @Param("theFloor") Long theFloor); } diff --git a/ruoyi-admin/src/main/resources/mapper/out/DenseLaneMapper.xml b/ruoyi-admin/src/main/resources/mapper/out/DenseLaneMapper.xml index af5e0bb..c0a198a 100644 --- a/ruoyi-admin/src/main/resources/mapper/out/DenseLaneMapper.xml +++ b/ruoyi-admin/src/main/resources/mapper/out/DenseLaneMapper.xml @@ -219,6 +219,53 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" target_space.cargo_space_id asc + +