package com.klp.service.impl; import cn.hutool.core.bean.BeanUtil; import cn.hutool.core.collection.CollUtil; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper; import com.baomidou.mybatisplus.core.toolkit.Wrappers; import com.klp.common.exception.ServiceException; import com.klp.common.utils.StringUtils; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; 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; import com.klp.domain.WmsActualWarehouse; import com.klp.mapper.WmsActualWarehouseMapper; import com.klp.service.IWmsActualWarehouseService; import com.klp.domain.WmsMaterialCoil; import com.klp.mapper.WmsMaterialCoilMapper; import java.util.*; import java.util.stream.Collectors; /** * 实际库区/库位自关联Service业务层处理 * * @author klp * @date 2025-11-24 */ @RequiredArgsConstructor @Service public class WmsActualWarehouseServiceImpl implements IWmsActualWarehouseService { private final WmsActualWarehouseMapper baseMapper; private final WmsMaterialCoilMapper wmsMaterialCoilMapper; /** * 查询实际库区/库位自关联 */ @Override public WmsActualWarehouseVo queryById(Long actualWarehouseId) { return baseMapper.selectVoById(actualWarehouseId); } /** * 释放实际库区/库位: * 1) 将该库区设置为未被占用(isEnabled=1) * 2) 清空钢卷表中绑定此库区且为现存(data_type=1)、未删除(del_flag=0)的记录的 actual_warehouse_id */ @Override @Transactional(rollbackFor = Exception.class) public void releaseActualWarehouse(Long actualWarehouseId) { if (actualWarehouseId == null || actualWarehouseId <= 0) { throw new ServiceException("参数actualWarehouseId不合法"); } // 1) 设置库区为启用(未被占用) WmsActualWarehouse update = new WmsActualWarehouse(); update.setActualWarehouseId(actualWarehouseId); update.setIsEnabled(1); int affected = baseMapper.updateById(update); if (affected <= 0) { // 不存在也提示 throw new ServiceException("实际库区不存在或更新失败: " + actualWarehouseId); } // 2) 清空钢卷绑定(仅现存且未删除)- 使用UpdateWrapper进行更新 UpdateWrapper updateWrapper = new UpdateWrapper<>(); updateWrapper.eq("actual_warehouse_id", actualWarehouseId) .eq("data_type", 1) .eq("del_flag", 0) .set("actual_warehouse_id", null); wmsMaterialCoilMapper.update(null, updateWrapper); } @Override @Transactional(rollbackFor = Exception.class) public int batchGenerateLocations(WmsActualWarehouseBatchGenerateBo bo) { if (bo == null) { throw new ServiceException("参数不能为空"); } Integer rows = bo.getRowCount(); Integer cols = bo.getColumnCount(); Integer layers = bo.getLayerCount(); String prefix = bo.getPrefix(); Long parentId = bo.getParentId(); if (layers == null) { layers = 2; } if (rows == null || cols == null || rows < 1 || cols < 1) { throw new ServiceException("行/列必须为正整数"); } if (layers < 1) { throw new ServiceException("层必须为正整数"); } if (StringUtils.isBlank(prefix)) { throw new ServiceException("前缀不能为空"); } List codes = new ArrayList<>(rows * cols * layers); for (int l = 1; l <= layers; l++) { int rowsForLayer = (l == 2) ? Math.max(rows - 1, 1) : rows; for (int c = 1; c <= cols; c++) { // 列直接显示数字(1→1,10→10,无需补0) String cStr = String.valueOf(c); for (int r = 1; r <= rowsForLayer; r++) { // 行的逻辑(1→01,10→10) String rStr = r < 10 ? ("0" + r) : String.valueOf(r); // 拼接编码:前缀 + 列 + - + 行 + - + 层 String code = prefix + cStr + '-' + rStr + '-' + l; codes.add(code); } } } // 去重:过滤同父级下已存在的编码 List exists = baseMapper.selectList(Wrappers.lambdaQuery() .eq(WmsActualWarehouse::getParentId, parentId) .in(!codes.isEmpty(), WmsActualWarehouse::getActualWarehouseCode, codes)); Set existCodes = exists.stream().map(WmsActualWarehouse::getActualWarehouseCode).collect(Collectors.toSet()); List toInsert = new ArrayList<>(); for (String code : codes) { if (existCodes.contains(code)) { continue; } WmsActualWarehouse e = new WmsActualWarehouse(); e.setParentId(parentId); e.setActualWarehouseType(3L); e.setActualWarehouseCode(code); e.setActualWarehouseName(code); e.setSortNo(0L); e.setIsEnabled(1); toInsert.add(e); } if (toInsert.isEmpty()) { return 0; } boolean ok = baseMapper.insertBatch(toInsert); if (!ok) { throw new ServiceException("批量生成失败"); } return toInsert.size(); } /** * 查询实际库区/库位自关联列表 */ @Override public List queryList(WmsActualWarehouseBo bo) { LambdaQueryWrapper lqw = buildQueryWrapper(bo); List list = baseMapper.selectVoList(lqw); if (CollUtil.isEmpty(list)) { 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::getActualWarehouseCode, 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) .map(WmsActualWarehouseVo::getActualWarehouseId) .filter(Objects::nonNull) .distinct() .collect(Collectors.toList()); if (CollUtil.isEmpty(occupiedAwIds)) { return list; } // 查询当前在库(del_flag=0, status=0)并且占用这些库位的钢卷,仅选择必要列 List coils = wmsMaterialCoilMapper.selectList( Wrappers.lambdaQuery() .select( WmsMaterialCoil::getActualWarehouseId, WmsMaterialCoil::getCoilId, WmsMaterialCoil::getEnterCoilNo, WmsMaterialCoil::getCurrentCoilNo, WmsMaterialCoil::getSupplierCoilNo ) .in(WmsMaterialCoil::getActualWarehouseId, occupiedAwIds) .eq(WmsMaterialCoil::getDataType, 1) .eq(WmsMaterialCoil::getDelFlag, 0) .eq(WmsMaterialCoil::getStatus, 0) ); if (CollUtil.isEmpty(coils)) { return list; } // 同一库位若有多条记录,选择最新一条(按更新顺序无字段,这里按主键最大) Map coilByAwId = coils.stream() .collect(Collectors.toMap( WmsMaterialCoil::getActualWarehouseId, c -> c, (a, b) -> a.getCoilId() != null && b.getCoilId() != null && a.getCoilId() > b.getCoilId() ? a : b )); list.forEach(it -> { if (it.getIsEnabled() != null && it.getIsEnabled() == 0) { WmsMaterialCoil c = coilByAwId.get(it.getActualWarehouseId()); if (c != null) { it.setEnterCoilNo(c.getEnterCoilNo()); it.setCurrentCoilNo(c.getCurrentCoilNo()); it.setSupplierCoilNo(c.getSupplierCoilNo()); } } }); return list; } @Override public List queryTree(WmsActualWarehouseBo bo) { if (bo == null) { bo = new WmsActualWarehouseBo(); } LambdaQueryWrapper wrapper = Wrappers.lambdaQuery(); wrapper.eq(StringUtils.isNotBlank(bo.getActualWarehouseCode()), WmsActualWarehouse::getActualWarehouseCode, bo.getActualWarehouseCode()); wrapper.like(StringUtils.isNotBlank(bo.getActualWarehouseName()), WmsActualWarehouse::getActualWarehouseName, bo.getActualWarehouseName()); wrapper.eq(bo.getActualWarehouseType() != null, WmsActualWarehouse::getActualWarehouseType, bo.getActualWarehouseType()); wrapper.eq(bo.getIsEnabled() != null, WmsActualWarehouse::getIsEnabled, bo.getIsEnabled()); wrapper.orderByAsc(WmsActualWarehouse::getSortNo, WmsActualWarehouse::getActualWarehouseId); List flatList = baseMapper.selectVoList(wrapper); Map nodeMap = new LinkedHashMap<>(); flatList.forEach(item -> { WmsActualWarehouseTreeVo node = new WmsActualWarehouseTreeVo(); BeanUtil.copyProperties(item, node); nodeMap.put(node.getActualWarehouseId(), node); }); List roots = new ArrayList<>(); nodeMap.values().forEach(node -> { Long parentId = Optional.ofNullable(node.getParentId()).orElse(0L); if (parentId == 0 || !nodeMap.containsKey(parentId)) { roots.add(node); } else { nodeMap.get(parentId).getChildren().add(node); } }); return roots; } @Override public List queryTreeExcludeLevelThree(WmsActualWarehouseBo bo) { if (bo == null) { bo = new WmsActualWarehouseBo(); } // 设置查询条件,排除三级节点(actualWarehouseType=3) LambdaQueryWrapper wrapper = Wrappers.lambdaQuery(); wrapper.eq(StringUtils.isNotBlank(bo.getActualWarehouseCode()), WmsActualWarehouse::getActualWarehouseCode, bo.getActualWarehouseCode()); wrapper.like(StringUtils.isNotBlank(bo.getActualWarehouseName()), WmsActualWarehouse::getActualWarehouseName, bo.getActualWarehouseName()); wrapper.eq(bo.getActualWarehouseType() != null, WmsActualWarehouse::getActualWarehouseType, bo.getActualWarehouseType()); wrapper.eq(bo.getIsEnabled() != null, WmsActualWarehouse::getIsEnabled, bo.getIsEnabled()); // 排除三级节点(类型为3的节点) wrapper.ne(WmsActualWarehouse::getActualWarehouseType, 3); // 四级节点也排除 wrapper.ne(WmsActualWarehouse::getActualWarehouseType, 4); wrapper.orderByAsc(WmsActualWarehouse::getSortNo, WmsActualWarehouse::getActualWarehouseId); List flatList = baseMapper.selectVoList(wrapper); Map nodeMap = new LinkedHashMap<>(); flatList.forEach(item -> { WmsActualWarehouseTreeVo node = new WmsActualWarehouseTreeVo(); BeanUtil.copyProperties(item, node); nodeMap.put(node.getActualWarehouseId(), node); }); List roots = new ArrayList<>(); nodeMap.values().forEach(node -> { Long parentId = Optional.ofNullable(node.getParentId()).orElse(0L); if (parentId == 0 || !nodeMap.containsKey(parentId)) { roots.add(node); } else { nodeMap.get(parentId).getChildren().add(node); } }); return roots; } private LambdaQueryWrapper buildQueryWrapper(WmsActualWarehouseBo bo) { Map params = bo.getParams(); LambdaQueryWrapper lqw = Wrappers.lambdaQuery(); lqw.eq(bo.getParentId() != null, WmsActualWarehouse::getParentId, bo.getParentId()); lqw.eq(StringUtils.isNotBlank(bo.getActualWarehouseCode()), WmsActualWarehouse::getActualWarehouseCode, bo.getActualWarehouseCode()); lqw.like(StringUtils.isNotBlank(bo.getActualWarehouseName()), WmsActualWarehouse::getActualWarehouseName, bo.getActualWarehouseName()); lqw.eq(bo.getActualWarehouseType() != null, WmsActualWarehouse::getActualWarehouseType, bo.getActualWarehouseType()); lqw.eq(bo.getSortNo() != null, WmsActualWarehouse::getSortNo, bo.getSortNo()); lqw.eq(bo.getIsEnabled() != null, WmsActualWarehouse::getIsEnabled, bo.getIsEnabled()); return lqw; } /** * 新增实际库区/库位自关联 */ @Override public Boolean insertByBo(WmsActualWarehouseBo bo) { WmsActualWarehouse add = BeanUtil.toBean(bo, WmsActualWarehouse.class); validEntityBeforeSave(add); boolean flag = baseMapper.insert(add) > 0; if (flag) { bo.setActualWarehouseId(add.getActualWarehouseId()); } return flag; } /** * 修改实际库区/库位自关联 */ @Override public Boolean updateByBo(WmsActualWarehouseBo bo) { WmsActualWarehouse update = BeanUtil.toBean(bo, WmsActualWarehouse.class); validEntityBeforeSave(update); return baseMapper.updateById(update) > 0; } @Override @Transactional(rollbackFor = Exception.class) public List createHierarchy(WmsActualWarehouseHierarchyBo bo) { if (bo.getLevels() == null || bo.getLevels().isEmpty()) { throw new ServiceException("层级数据不能为空"); } List sortedLevels = bo.getLevels().stream() .sorted(Comparator.comparing(WmsActualWarehouseHierarchyBo.HierarchyLevel::getLevel)) .collect(Collectors.toList()); Long parentId = 0L; List createdIds = new ArrayList<>(); for (WmsActualWarehouseHierarchyBo.HierarchyLevel level : sortedLevels) { Integer levelValue = level.getLevel(); if (levelValue == null || levelValue < 1 || levelValue > 3) { throw new ServiceException("层级必须在1-3之间"); } if (level.getActualWarehouseId() != null) { WmsActualWarehouse existing = baseMapper.selectById(level.getActualWarehouseId()); if (existing == null) { throw new ServiceException("指定的节点不存在:" + level.getActualWarehouseId()); } if (!Objects.equals(Optional.ofNullable(existing.getParentId()).orElse(0L), parentId)) { throw new ServiceException("节点不属于当前父级,无法复用"); } parentId = existing.getActualWarehouseId(); continue; } if (StringUtils.isBlank(level.getActualWarehouseCode()) || StringUtils.isBlank(level.getActualWarehouseName())) { throw new ServiceException("编码与名称不能为空"); } WmsActualWarehouse duplicate = baseMapper.selectOne(Wrappers.lambdaQuery() .eq(WmsActualWarehouse::getParentId, parentId) .and(wrapper -> wrapper.eq(WmsActualWarehouse::getActualWarehouseCode, level.getActualWarehouseCode()) .or() .eq(WmsActualWarehouse::getActualWarehouseName, level.getActualWarehouseName()))); if (duplicate != null) { parentId = duplicate.getActualWarehouseId(); continue; } WmsActualWarehouse entity = new WmsActualWarehouse(); entity.setParentId(parentId); entity.setActualWarehouseType(levelValue.longValue()); entity.setActualWarehouseCode(level.getActualWarehouseCode()); entity.setActualWarehouseName(level.getActualWarehouseName()); entity.setSortNo(Optional.ofNullable(level.getSortNo()).orElse(0L)); entity.setIsEnabled(Optional.ofNullable(level.getIsEnabled()).orElse(1)); entity.setRemark(level.getRemark()); baseMapper.insert(entity); parentId = entity.getActualWarehouseId(); createdIds.add(parentId); } return createdIds; } @Override @Transactional(rollbackFor = Exception.class) public void importHierarchy(List importList) { if (CollUtil.isEmpty(importList)) { throw new ServiceException("导入数据不能为空"); } for (WmsActualWarehouseImportVo row : importList) { List levels = new ArrayList<>(); appendLevel(levels, 1, row.getLevelOneCode(), row.getLevelOneName(), row.getLevelOneSort()); appendLevel(levels, 2, row.getLevelTwoCode(), row.getLevelTwoName(), row.getLevelTwoSort()); appendLevel(levels, 3, row.getLevelThreeCode(), row.getLevelThreeName(), row.getLevelThreeSort()); if (levels.isEmpty()) { continue; } WmsActualWarehouseHierarchyBo bo = new WmsActualWarehouseHierarchyBo(); bo.setLevels(levels); createHierarchy(bo); } } /** * 保存前的数据校验 */ private void validEntityBeforeSave(WmsActualWarehouse entity) { //TODO 做一些数据校验,如唯一约束 } private void appendLevel(List levels, int level, String code, String name, Long sortNo) { if (StringUtils.isBlank(code) || StringUtils.isBlank(name)) { return; } WmsActualWarehouseHierarchyBo.HierarchyLevel item = new WmsActualWarehouseHierarchyBo.HierarchyLevel(); item.setLevel(level); item.setActualWarehouseCode(code.trim()); item.setActualWarehouseName(name.trim()); item.setSortNo(Optional.ofNullable(sortNo).orElse(0L)); item.setIsEnabled(1); levels.add(item); } /** * 批量删除实际库区/库位自关联 */ @Override public Boolean deleteWithValidByIds(Collection ids, Boolean isValid) { if (isValid) { //TODO 做一些业务上的校验,判断是否需要校验 } return baseMapper.deleteBatchIds(ids) > 0; } @Override @Transactional(rollbackFor = Exception.class) public void splitLocations(WmsActualWarehouseSplitBo bo) { if (bo == null) { throw new ServiceException("参数不能为空"); } // 参数验证 String columnFlag = bo.getColumnFlag(); if (StringUtils.isBlank(columnFlag)) { throw new ServiceException("列标识不能为空"); } int splitType = Optional.ofNullable(bo.getSplitType()).orElse(0); List Ids = Optional.ofNullable(bo.getSplitIds()).orElse(new ArrayList<>()); // 合并所有待拆分的ID Set splitIds = new HashSet<>(); splitIds.addAll(Ids); if (splitIds.isEmpty()) { throw new ServiceException("待拆分库位ID列表不能为空"); } // 根据列标识查询该列的所有库位(第一层和第二层) List columnLocations = baseMapper.selectList(Wrappers.lambdaQuery() .likeRight(WmsActualWarehouse::getActualWarehouseCode, columnFlag + "-") .eq(WmsActualWarehouse::getDelFlag, 0) .eq(WmsActualWarehouse::getActualWarehouseType, 3) // 只查询三级库位 .orderByAsc(WmsActualWarehouse::getActualWarehouseCode)); if (CollUtil.isEmpty(columnLocations)) { throw new ServiceException("未找到列标识为 " + columnFlag + " 的库位"); } // 检查整个列中是否有任何库位被占用 List occupiedCodes = new ArrayList<>(); for (WmsActualWarehouse location : columnLocations) { // 锁定状态=0 → 被占用 boolean isOccupied = location.getIsEnabled() != null && location.getIsEnabled() == 0; if (isOccupied) { occupiedCodes.add(location.getActualWarehouseCode()); } } // 如果有任何库位被占用,抛出异常提示 if (!occupiedCodes.isEmpty()) { throw new ServiceException("以下库位被占用,无法拆分:" + String.join(",", occupiedCodes)); } // 批量查询所有子库位(一次性查询,避免循环查询) List parentIds = columnLocations.stream() .map(WmsActualWarehouse::getActualWarehouseId) .collect(Collectors.toList()); List allChildren = baseMapper.selectList(Wrappers.lambdaQuery() .in(WmsActualWarehouse::getParentId, parentIds) .eq(WmsActualWarehouse::getActualWarehouseType, 4)); // 四级子库位 boolean hasExistingChildren = CollUtil.isNotEmpty(allChildren); if (hasExistingChildren) { // 如果已经有子库位,执行复活逻辑 reviveExistingSubLocations(columnLocations, splitIds, splitType, allChildren); } else { // 如果没有子库位,执行创建逻辑 createNewSubLocationsWithOriginalLogic(columnLocations, splitIds, splitType, columnFlag); } // 批量更新该列所有被拆分库位的状态 List toUpdate = new ArrayList<>(); for (WmsActualWarehouse location : columnLocations) { WmsActualWarehouse upd = new WmsActualWarehouse(); upd.setActualWarehouseId(location.getActualWarehouseId()); upd.setSplitStatus(1); upd.setSplitType(splitType); toUpdate.add(upd); } if (!toUpdate.isEmpty()) { baseMapper.updateBatchById(toUpdate); } } /** * 复活已存在的子库位(优化版:批量操作) */ private void reviveExistingSubLocations(List columnLocations, Set splitIds, Integer splitType, List allChildren) { // 按父ID分组子库位 Map> childrenByParent = allChildren.stream() .sorted(Comparator.comparing(WmsActualWarehouse::getActualWarehouseId)) .collect(Collectors.groupingBy(WmsActualWarehouse::getParentId, LinkedHashMap::new, Collectors.toList())); List toUpdate = new ArrayList<>(); for (WmsActualWarehouse location : columnLocations) { boolean isSplitLocation = splitIds.contains(location.getActualWarehouseId()); List children = childrenByParent.get(location.getActualWarehouseId()); if (CollUtil.isEmpty(children)) { continue; } // 根据是否为拆分库位决定需要复活的子库位数量 int requiredCount = isSplitLocation ? 2 : 1; // 复活前N个子库位 for (int i = 0; i < Math.min(requiredCount, children.size()); i++) { WmsActualWarehouse child = children.get(i); if (child.getDelFlag() == 1) { // 只处理已删除的子库位 WmsActualWarehouse childUpdate = new WmsActualWarehouse(); childUpdate.setActualWarehouseId(child.getActualWarehouseId()); childUpdate.setDelFlag(0); childUpdate.setSplitStatus(1); childUpdate.setSplitType(splitType); toUpdate.add(childUpdate); } } // 如果子库位数量超过需要的数量,隐藏多余的 if (children.size() > requiredCount) { for (int i = requiredCount; i < children.size(); i++) { WmsActualWarehouse child = children.get(i); if (child.getDelFlag() == 0) { // 只处理未删除的子库位 WmsActualWarehouse childUpdate = new WmsActualWarehouse(); childUpdate.setActualWarehouseId(child.getActualWarehouseId()); childUpdate.setDelFlag(1); toUpdate.add(childUpdate); } } } } // 批量更新 if (!toUpdate.isEmpty()) { baseMapper.updateBatchById(toUpdate); } } /** * 使用逻辑创建新的子库位 */ private void createNewSubLocationsWithOriginalLogic(List columnLocations, Set splitIds, Integer splitType, String columnFlag) { // 分离需要拆分的库位和剩余库位 List splitLocations = new ArrayList<>(); List remainingLocations = new ArrayList<>(); for (WmsActualWarehouse location : columnLocations) { if (splitIds.contains(location.getActualWarehouseId())) { splitLocations.add(location); } else { remainingLocations.add(location); } } // 第一步:先创建所有子库位(不设置编码) List toInsert = new ArrayList<>(); // 1. 处理需要拆分的库位(每个拆分为2个子库位) for (WmsActualWarehouse location : splitLocations) { // 生成第一个子库位 WmsActualWarehouse subLocation1 = new WmsActualWarehouse(); subLocation1.setParentId(location.getActualWarehouseId()); subLocation1.setActualWarehouseType(4L); // 四级节点 subLocation1.setSortNo(Optional.ofNullable(location.getSortNo()).orElse(0L)); subLocation1.setIsEnabled(1); subLocation1.setSplitStatus(1); subLocation1.setSplitType(splitType); toInsert.add(subLocation1); // 生成第二个子库位 WmsActualWarehouse subLocation2 = new WmsActualWarehouse(); subLocation2.setParentId(location.getActualWarehouseId()); subLocation2.setActualWarehouseType(4L); // 四级节点 subLocation2.setSortNo(Optional.ofNullable(location.getSortNo()).orElse(0L)); subLocation2.setIsEnabled(1); subLocation2.setSplitStatus(1); subLocation2.setSplitType(splitType); toInsert.add(subLocation2); } // 2. 处理剩余库位(每个拆分为1个子库位,保持原层级) for (WmsActualWarehouse remainingLocation : remainingLocations) { // 生成剩余库位的子库位 WmsActualWarehouse remainingSubLocation = new WmsActualWarehouse(); remainingSubLocation.setParentId(remainingLocation.getActualWarehouseId()); remainingSubLocation.setActualWarehouseType(4L); // 四级节点 remainingSubLocation.setSortNo(Optional.ofNullable(remainingLocation.getSortNo()).orElse(0L)); remainingSubLocation.setIsEnabled(1); remainingSubLocation.setSplitStatus(1); remainingSubLocation.setSplitType(splitType); toInsert.add(remainingSubLocation); } // 3. 验证总数 int expectedSplitSubLocations = splitLocations.size() * 2; int expectedRemainingSubLocations = remainingLocations.size() * 1; int expectedTotalSubLocations = expectedSplitSubLocations + expectedRemainingSubLocations; int actualTotalSubLocations = toInsert.size(); if (actualTotalSubLocations != expectedTotalSubLocations) { throw new ServiceException(String.format( "子库位生成数量不匹配,期望%d个(拆分库位:%d个→%d个,剩余库位:%d个→%d个),实际生成%d个", expectedTotalSubLocations, splitLocations.size(), expectedSplitSubLocations, remainingLocations.size(), expectedRemainingSubLocations, actualTotalSubLocations )); } // 4. 批量插入子库位(先插入获取ID) if (!toInsert.isEmpty()) { boolean ok = baseMapper.insertBatch(toInsert); if (!ok) { throw new ServiceException("新增子库位失败"); } } // 第二步:重新生成编码 String prefix = columnFlag; List toUpdate = new ArrayList<>(); // 1. 先把所有子库位按父库位排序 List sortedSubLocations = new ArrayList<>(toInsert); sortedSubLocations.sort((a, b) -> { // 按父库位在原列中的顺序排序 Long parentA = a.getParentId(); Long parentB = b.getParentId(); int indexA = columnLocations.stream().map(WmsActualWarehouse::getActualWarehouseId).collect(Collectors.toList()).indexOf(parentA); int indexB = columnLocations.stream().map(WmsActualWarehouse::getActualWarehouseId).collect(Collectors.toList()).indexOf(parentB); return Integer.compare(indexA, indexB); }); // 2. 遍历排序后的子库位,每2个为一组生成编码(序号递增,后缀固定1、2) for (int i = 0; i < sortedSubLocations.size(); i++) { WmsActualWarehouse sub = sortedSubLocations.get(i); int sequenceNum = (i / 2) + 1; // 每2个子库位对应一个序号(0→1,1→1,2→2,3→2...) int layer = (i % 2) + 1; // 每组内固定1、2后缀(0→1,1→2,2→1,3→2...) // 生成编码:前缀-两位序号-层级(如F2B1-X01-1、F2B1-X01-2、F2B1-X02-1...) String newCode = String.format("%s-X%02d-%d", prefix, sequenceNum, layer); sub.setActualWarehouseCode(newCode); sub.setActualWarehouseName(newCode); toUpdate.add(sub); } // 3. 批量更新编码 if (!toUpdate.isEmpty()) { baseMapper.updateBatchById(toUpdate); } } @Override @Transactional(rollbackFor = Exception.class) public void mergeLocations(WmsActualWarehouseSplitBo bo) { if (bo == null) { throw new ServiceException("参数不能为空"); } // 获取列标识 String columnFlag = bo.getColumnFlag(); if (StringUtils.isBlank(columnFlag)) { throw new ServiceException("列标识不能为空"); } // 根据列标识查询该列的所有三级库位 List columnLocations = baseMapper.selectList(Wrappers.lambdaQuery() .likeRight(WmsActualWarehouse::getActualWarehouseCode, columnFlag + "-") .eq(WmsActualWarehouse::getDelFlag, 0) .eq(WmsActualWarehouse::getActualWarehouseType, 3) // 只查询三级库位 .orderByAsc(WmsActualWarehouse::getActualWarehouseCode)); if (CollUtil.isEmpty(columnLocations)) { throw new ServiceException("未找到列标识为 " + columnFlag + " 的库位"); } // 过滤出需要合并的库位(splitStatus=1) List locationsToMerge = columnLocations.stream() .filter(loc -> Optional.ofNullable(loc.getSplitStatus()).orElse(0) == 1) .collect(Collectors.toList()); if (CollUtil.isEmpty(locationsToMerge)) { return; // 没有需要合并的库位 } // 批量查询所有子库位 List parentIds = columnLocations.stream() .map(WmsActualWarehouse::getActualWarehouseId) .collect(Collectors.toList()); List allChildren = baseMapper.selectList(Wrappers.lambdaQuery() .in(WmsActualWarehouse::getParentId, parentIds) .eq(WmsActualWarehouse::getActualWarehouseType, 4)); // 四级子库位 // 检查整列中是否有任何子库位被占用 if (CollUtil.isNotEmpty(allChildren)) { boolean anyOccupied = allChildren.stream() .filter(c -> c.getDelFlag() == 0) .anyMatch(c -> !Objects.equals(c.getIsEnabled(), 1)); if (anyOccupied) { throw new ServiceException("该列存在被占用的子库位,不能合并"); } } // 批量更新子库位和父库位 List childrenToUpdate = new ArrayList<>(); List parentsToUpdate = new ArrayList<>(); for (WmsActualWarehouse location : locationsToMerge) { List children = allChildren.stream() .filter(c -> Objects.equals(c.getParentId(), location.getActualWarehouseId())) .collect(Collectors.toList()); // 隐藏所有子库位 if (CollUtil.isNotEmpty(children)) { for (WmsActualWarehouse child : children) { if (child.getDelFlag() == 0) { WmsActualWarehouse childUpdate = new WmsActualWarehouse(); childUpdate.setActualWarehouseId(child.getActualWarehouseId()); childUpdate.setDelFlag(1); childrenToUpdate.add(childUpdate); } } } // 更新父库位状态为未拆分 WmsActualWarehouse parentUpdate = new WmsActualWarehouse(); parentUpdate.setActualWarehouseId(location.getActualWarehouseId()); parentUpdate.setSplitStatus(0); parentUpdate.setSplitType(0); parentsToUpdate.add(parentUpdate); } // 批量更新 if (!childrenToUpdate.isEmpty()) { baseMapper.updateBatchById(childrenToUpdate); } if (!parentsToUpdate.isEmpty()) { baseMapper.updateBatchById(parentsToUpdate); } } }