From 7e415eb56e8f789903850ce2dbe21d49230f83f2 Mon Sep 17 00:00:00 2001 From: Joshi <3040996759@qq.com> Date: Fri, 19 Dec 2025 13:53:36 +0800 Subject: [PATCH] =?UTF-8?q?feat(wms):=20=E5=AE=9E=E7=8E=B0=E5=BA=93?= =?UTF-8?q?=E4=BD=8D=E6=8B=86=E5=88=86=E4=B8=8E=E5=90=88=E5=B9=B6=E5=8A=9F?= =?UTF-8?q?=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 新增库位拆分状态和类型字段,支持大库位拆分为两个小库位 - 新增拆分与合并接口,支持将三级库位进行拆分或合并操作 - 在查询时自动展开已拆分库位的子节点,显示其两个小库位 - 实现拆分时复用历史子库位逻辑,避免重复创建相同编码库位 - 添加拆分与合并时的业务校验,确保库位状态合法才可操作 - 提供 WmsActualWarehouseSplitBo 用于接收拆分/合并请求参数 - 完善实体类和 VO 类对拆分状态及类型的映射支持 - 更新 Mapper XML 配置以支持新增的拆分相关数据库字段 --- .../WmsActualWarehouseController.java | 21 ++ .../com/klp/domain/WmsActualWarehouse.java | 10 + .../klp/domain/bo/WmsActualWarehouseBo.java | 10 + .../domain/bo/WmsActualWarehouseSplitBo.java | 31 +++ .../klp/domain/vo/WmsActualWarehouseVo.java | 13 ++ .../service/IWmsActualWarehouseService.java | 11 + .../impl/WmsActualWarehouseServiceImpl.java | 188 ++++++++++++++++++ .../mapper/klp/WmsActualWarehouseMapper.xml | 2 + 8 files changed, 286 insertions(+) create mode 100644 klp-wms/src/main/java/com/klp/domain/bo/WmsActualWarehouseSplitBo.java diff --git a/klp-wms/src/main/java/com/klp/controller/WmsActualWarehouseController.java b/klp-wms/src/main/java/com/klp/controller/WmsActualWarehouseController.java index 7c22564b..b4714717 100644 --- a/klp-wms/src/main/java/com/klp/controller/WmsActualWarehouseController.java +++ b/klp-wms/src/main/java/com/klp/controller/WmsActualWarehouseController.java @@ -27,6 +27,7 @@ import com.klp.domain.vo.WmsActualWarehouseImportVo; import com.klp.domain.bo.WmsActualWarehouseBo; import com.klp.domain.bo.WmsActualWarehouseHierarchyBo; import com.klp.domain.bo.WmsActualWarehouseBatchGenerateBo; +import com.klp.domain.bo.WmsActualWarehouseSplitBo; import com.klp.service.IWmsActualWarehouseService; /** @@ -138,6 +139,26 @@ public class WmsActualWarehouseController extends BaseController { return R.ok(created); } + /** + * 拆分指定库位(将某列/选中/全部的三级库位拆成2个小库位) + */ + @Log(title = "实际库区/库位-拆分", businessType = BusinessType.UPDATE) + @PostMapping("/split") + public R split(@Validated @RequestBody WmsActualWarehouseSplitBo bo) { + iWmsActualWarehouseService.splitLocations(bo); + return R.ok(); + } + + /** + * 合并指定库位(将已拆分的小库位还原为大库位) + */ + @Log(title = "实际库区/库位-合并", businessType = BusinessType.UPDATE) + @PostMapping("/merge") + public R merge(@Validated @RequestBody WmsActualWarehouseSplitBo bo) { + iWmsActualWarehouseService.mergeLocations(bo); + return R.ok(); + } + /** * 修改实际库区/库位自关联 */ diff --git a/klp-wms/src/main/java/com/klp/domain/WmsActualWarehouse.java b/klp-wms/src/main/java/com/klp/domain/WmsActualWarehouse.java index a6acaadc..014a1638 100644 --- a/klp-wms/src/main/java/com/klp/domain/WmsActualWarehouse.java +++ b/klp-wms/src/main/java/com/klp/domain/WmsActualWarehouse.java @@ -48,6 +48,16 @@ public class WmsActualWarehouse extends TreeEntity { * 是否启用(0=否,1=是) */ private Integer isEnabled; + /** + * 拆分状态:0=未拆分(大库位),1=已拆分(小库位) + */ + @TableField("split_status") + private Integer splitStatus; + /** + * 拆分类型(仅当split_status=1时有效):0=列拆分(1列拆2小库位) + */ + @TableField("split_type") + private Integer splitType; /** * 删除标志(0=正常,1=已删除) */ diff --git a/klp-wms/src/main/java/com/klp/domain/bo/WmsActualWarehouseBo.java b/klp-wms/src/main/java/com/klp/domain/bo/WmsActualWarehouseBo.java index 60ee0ab5..9819fe3f 100644 --- a/klp-wms/src/main/java/com/klp/domain/bo/WmsActualWarehouseBo.java +++ b/klp-wms/src/main/java/com/klp/domain/bo/WmsActualWarehouseBo.java @@ -52,6 +52,16 @@ public class WmsActualWarehouseBo extends TreeEntity { */ private Integer isEnabled; + /** + * 拆分状态:0=未拆分(大库位),1=已拆分(小库位)或已被拆分 + */ + private Integer splitStatus; + + /** + * 拆分类型:0=列拆分 + */ + private Integer splitType; + /** * 备注 */ diff --git a/klp-wms/src/main/java/com/klp/domain/bo/WmsActualWarehouseSplitBo.java b/klp-wms/src/main/java/com/klp/domain/bo/WmsActualWarehouseSplitBo.java new file mode 100644 index 00000000..ee83ba6d --- /dev/null +++ b/klp-wms/src/main/java/com/klp/domain/bo/WmsActualWarehouseSplitBo.java @@ -0,0 +1,31 @@ +package com.klp.domain.bo; + +import lombok.Data; + +import javax.validation.constraints.NotEmpty; +import javax.validation.constraints.NotNull; +import java.util.List; + +/** + * 库位拆分/合并请求 + */ +@Data +public class WmsActualWarehouseSplitBo { + + /** + * 需要操作的三级库位ID集合(大库位ID) + */ + @NotEmpty + private List locationIds; + + /** + * 操作类型:1=拆分,0=合并 + */ + @NotNull + private Integer action; + + /** + * 拆分类型:目前仅支持 0=列拆分 + */ + private Integer splitType = 0; +} diff --git a/klp-wms/src/main/java/com/klp/domain/vo/WmsActualWarehouseVo.java b/klp-wms/src/main/java/com/klp/domain/vo/WmsActualWarehouseVo.java index 1757da65..4d2a3242 100644 --- a/klp-wms/src/main/java/com/klp/domain/vo/WmsActualWarehouseVo.java +++ b/klp-wms/src/main/java/com/klp/domain/vo/WmsActualWarehouseVo.java @@ -63,6 +63,16 @@ public class WmsActualWarehouseVo { @ExcelDictFormat(readConverterExp = "0==否,1=是") private Integer isEnabled; + /** + * 拆分状态:0=未拆分,1=已拆分 + */ + private Integer splitStatus; + + /** + * 拆分类型:0=列拆分 + */ + private Integer splitType; + /** * 备注 */ @@ -74,5 +84,8 @@ public class WmsActualWarehouseVo { private String currentCoilNo; private String supplierCoilNo; + // 当该节点被拆分时,返回其子节点(两个小库位) + private java.util.List children; + } diff --git a/klp-wms/src/main/java/com/klp/service/IWmsActualWarehouseService.java b/klp-wms/src/main/java/com/klp/service/IWmsActualWarehouseService.java index f8a52f1a..af128067 100644 --- a/klp-wms/src/main/java/com/klp/service/IWmsActualWarehouseService.java +++ b/klp-wms/src/main/java/com/klp/service/IWmsActualWarehouseService.java @@ -6,6 +6,7 @@ import com.klp.domain.vo.WmsActualWarehouseImportVo; import com.klp.domain.bo.WmsActualWarehouseBo; import com.klp.domain.bo.WmsActualWarehouseHierarchyBo; import com.klp.domain.bo.WmsActualWarehouseBatchGenerateBo; +import com.klp.domain.bo.WmsActualWarehouseSplitBo; import java.util.Collection; import java.util.List; @@ -66,4 +67,14 @@ public interface IWmsActualWarehouseService { * @return 成功创建数量 */ int batchGenerateLocations(WmsActualWarehouseBatchGenerateBo bo); + + /** + * 将给定的三级库位拆分为两个小库位 + */ + void splitLocations(WmsActualWarehouseSplitBo bo); + + /** + * 将已拆分的库位合并回一个大库位 + */ + void mergeLocations(WmsActualWarehouseSplitBo bo); } diff --git a/klp-wms/src/main/java/com/klp/service/impl/WmsActualWarehouseServiceImpl.java b/klp-wms/src/main/java/com/klp/service/impl/WmsActualWarehouseServiceImpl.java index ce8fb493..3b722d1f 100644 --- a/klp-wms/src/main/java/com/klp/service/impl/WmsActualWarehouseServiceImpl.java +++ b/klp-wms/src/main/java/com/klp/service/impl/WmsActualWarehouseServiceImpl.java @@ -12,6 +12,7 @@ import org.springframework.transaction.annotation.Transactional; import com.klp.domain.bo.WmsActualWarehouseBo; import com.klp.domain.bo.WmsActualWarehouseHierarchyBo; import com.klp.domain.bo.WmsActualWarehouseBatchGenerateBo; +import com.klp.domain.bo.WmsActualWarehouseSplitBo; import com.klp.domain.vo.WmsActualWarehouseTreeVo; import com.klp.domain.vo.WmsActualWarehouseImportVo; import com.klp.domain.vo.WmsActualWarehouseVo; @@ -124,6 +125,36 @@ public class WmsActualWarehouseServiceImpl implements IWmsActualWarehouseService return list; } + // 如果当前查询的是某二级父节点下的三级库位,需要将被拆分的大库位替换为其两个子库位 + if (bo.getParentId() != null) { + List splitParentIds = list.stream() + .filter(v -> Optional.ofNullable(v.getSplitStatus()).orElse(0) == 1) + .map(WmsActualWarehouseVo::getActualWarehouseId) + .collect(Collectors.toList()); + if (CollUtil.isNotEmpty(splitParentIds)) { + List children = baseMapper.selectVoList( + Wrappers.lambdaQuery() + .in(WmsActualWarehouse::getParentId, splitParentIds) + .eq(WmsActualWarehouse::getDelFlag, 0) + .orderByAsc(WmsActualWarehouse::getSortNo, WmsActualWarehouse::getActualWarehouseId) + ); + Map> childrenMap = children.stream() + .collect(Collectors.groupingBy(WmsActualWarehouseVo::getParentId, LinkedHashMap::new, Collectors.toList())); + List expanded = new ArrayList<>(list.size() + children.size()); + for (WmsActualWarehouseVo v : list) { + if (Optional.ofNullable(v.getSplitStatus()).orElse(0) == 1) { + List ch = childrenMap.get(v.getActualWarehouseId()); + if (CollUtil.isNotEmpty(ch)) { + expanded.addAll(ch); + continue; + } + } + expanded.add(v); + } + list = expanded; + } + } + // 仅对被占用的位置(isEnabled=0)补充钢卷信息 List occupiedAwIds = list.stream() .filter(it -> it.getIsEnabled() != null && it.getIsEnabled() == 0) @@ -386,5 +417,162 @@ public class WmsActualWarehouseServiceImpl implements IWmsActualWarehouseService return baseMapper.deleteBatchIds(ids) > 0; } + @Override + @Transactional(rollbackFor = Exception.class) + public void splitLocations(WmsActualWarehouseSplitBo bo) { + if (bo == null || CollUtil.isEmpty(bo.getLocationIds())) { + throw new ServiceException("参数不能为空"); + } + int splitType = Optional.ofNullable(bo.getSplitType()).orElse(0); + // 仅允许列拆分(1拆2)的类型,防止非法拆分类型 + if (splitType != 0) { + throw new ServiceException("暂仅支持列拆分(1拆2)"); + } + // 查询父库位并校验有效性 + List locationIds = bo.getLocationIds(); + List parents = baseMapper.selectList(Wrappers.lambdaQuery() + .in(WmsActualWarehouse::getActualWarehouseId, locationIds) + .eq(WmsActualWarehouse::getDelFlag, 0)); + // 校验无效ID并明确提示 + Set existIds = parents.stream().map(WmsActualWarehouse::getActualWarehouseId).collect(Collectors.toSet()); + List invalidIds = locationIds.stream().filter(id -> !existIds.contains(id)).collect(Collectors.toList()); + if (!invalidIds.isEmpty()) { + throw new ServiceException("存在无效库位ID:" + invalidIds); + } + // 检查占用与状态:仅依据 isEnabled=1 为未占用,可拆分 + for (WmsActualWarehouse p : parents) { + Integer st = Optional.ofNullable(p.getSplitStatus()).orElse(0); + if (st == 1) { + throw new ServiceException("库位已拆分:" + p.getActualWarehouseCode()); + } + if (!Objects.equals(p.getIsEnabled(), 1)) { + throw new ServiceException("库位被占用或禁用,不能拆分:" + p.getActualWarehouseCode()); + } + } + List toInsert = new ArrayList<>(); + for (WmsActualWarehouse p : parents) { + String base = p.getActualWarehouseCode(); + // 先查找是否存在历史子库位(逻辑删除状态) + List historyChildren = baseMapper.selectList( + Wrappers.lambdaQuery() + .eq(WmsActualWarehouse::getParentId, p.getActualWarehouseId()) + .in(WmsActualWarehouse::getActualWarehouseCode, Arrays.asList(base + "-1", base + "-2")) + .eq(WmsActualWarehouse::getDelFlag, 1) + ); + if (CollUtil.isNotEmpty(historyChildren)) { + // 复活历史子库位,避免新建,保持原ID和二维码 + for (WmsActualWarehouse his : historyChildren) { + WmsActualWarehouse revive = new WmsActualWarehouse(); + revive.setActualWarehouseId(his.getActualWarehouseId()); + revive.setDelFlag(0); + revive.setSplitStatus(1); + revive.setSplitType(splitType); + revive.setIsEnabled(1); + baseMapper.updateById(revive); + } + // 如果只找到了一个历史子库位,另一个需要新建 + if (historyChildren.size() < 2) { + Set found = historyChildren.stream().map(WmsActualWarehouse::getActualWarehouseCode).collect(Collectors.toSet()); + String miss = !found.contains(base + "-1") ? base + "-1" : base + "-2"; + WmsActualWarehouse c = new WmsActualWarehouse(); + c.setParentId(p.getActualWarehouseId()); + c.setActualWarehouseType(p.getActualWarehouseType()); + c.setActualWarehouseCode(miss); + c.setActualWarehouseName(miss); + c.setSortNo(Optional.ofNullable(p.getSortNo()).orElse(0L)); + c.setIsEnabled(1); + c.setSplitStatus(1); + c.setSplitType(splitType); + toInsert.add(c); + } + } else { + // 无历史记录,则正常新建两个 + WmsActualWarehouse c1 = new WmsActualWarehouse(); + c1.setParentId(p.getActualWarehouseId()); + c1.setActualWarehouseType(p.getActualWarehouseType()); + c1.setActualWarehouseCode(base + "-1"); + c1.setActualWarehouseName(base + "-1"); + c1.setSortNo(Optional.ofNullable(p.getSortNo()).orElse(0L)); + c1.setIsEnabled(1); + c1.setSplitStatus(1); + c1.setSplitType(splitType); + toInsert.add(c1); + + WmsActualWarehouse c2 = new WmsActualWarehouse(); + c2.setParentId(p.getActualWarehouseId()); + c2.setActualWarehouseType(p.getActualWarehouseType()); + c2.setActualWarehouseCode(base + "-2"); + c2.setActualWarehouseName(base + "-2"); + c2.setSortNo(Optional.ofNullable(p.getSortNo()).orElse(0L)); + c2.setIsEnabled(1); + c2.setSplitStatus(1); + c2.setSplitType(splitType); + toInsert.add(c2); + } + } + if (!toInsert.isEmpty()) { + boolean ok = baseMapper.insertBatch(toInsert); + if (!ok) { + throw new ServiceException("新增小库位失败"); + } + } + // 更新父节点拆分状态 + for (WmsActualWarehouse p : parents) { + WmsActualWarehouse upd = new WmsActualWarehouse(); + upd.setActualWarehouseId(p.getActualWarehouseId()); + upd.setSplitStatus(1); + upd.setSplitType(splitType); + baseMapper.updateById(upd); + } + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void mergeLocations(WmsActualWarehouseSplitBo bo) { + if (bo == null || CollUtil.isEmpty(bo.getLocationIds())) { + throw new ServiceException("参数不能为空"); + } + List parents = baseMapper.selectList(Wrappers.lambdaQuery() + .in(WmsActualWarehouse::getActualWarehouseId, bo.getLocationIds()) + .eq(WmsActualWarehouse::getDelFlag, 0)); + for (WmsActualWarehouse p : parents) { + Integer st = Optional.ofNullable(p.getSplitStatus()).orElse(0); + if (st != 1) { + // 未拆分无需合并 + continue; + } + List children = baseMapper.selectList(Wrappers.lambdaQuery() + .eq(WmsActualWarehouse::getParentId, p.getActualWarehouseId()) + .eq(WmsActualWarehouse::getDelFlag, 0)); + if (CollUtil.isEmpty(children)) { + // 无子节点,直接还原状态 + WmsActualWarehouse upd = new WmsActualWarehouse(); + upd.setActualWarehouseId(p.getActualWarehouseId()); + upd.setSplitStatus(0); + upd.setSplitType(0); + baseMapper.updateById(upd); + continue; + } + // 检查子库位 isEnabled 必须为1(未占用) + boolean anyOccupied = children.stream().anyMatch(c -> !Objects.equals(c.getIsEnabled(), 1)); + if (anyOccupied) { + throw new ServiceException("小库位被占用,不能合并:" + p.getActualWarehouseCode()); + } + // 逻辑删除小库位 + for (WmsActualWarehouse c : children) { + WmsActualWarehouse updC = new WmsActualWarehouse(); + updC.setActualWarehouseId(c.getActualWarehouseId()); + updC.setDelFlag(1); + baseMapper.updateById(updC); + } + // 更新父状态 + WmsActualWarehouse upd = new WmsActualWarehouse(); + upd.setActualWarehouseId(p.getActualWarehouseId()); + upd.setSplitStatus(0); + upd.setSplitType(0); + baseMapper.updateById(upd); + } + } + } diff --git a/klp-wms/src/main/resources/mapper/klp/WmsActualWarehouseMapper.xml b/klp-wms/src/main/resources/mapper/klp/WmsActualWarehouseMapper.xml index e0777755..43b3211c 100644 --- a/klp-wms/src/main/resources/mapper/klp/WmsActualWarehouseMapper.xml +++ b/klp-wms/src/main/resources/mapper/klp/WmsActualWarehouseMapper.xml @@ -12,6 +12,8 @@ + +