diff --git a/klp-wms/src/main/java/com/klp/controller/WmsBatchController.java b/klp-wms/src/main/java/com/klp/controller/WmsBatchController.java index 7bd85729..901134a6 100644 --- a/klp-wms/src/main/java/com/klp/controller/WmsBatchController.java +++ b/klp-wms/src/main/java/com/klp/controller/WmsBatchController.java @@ -4,6 +4,7 @@ import java.util.List; import java.util.Arrays; import java.util.Map; +import com.klp.domain.vo.BatchGroupVo; import lombok.RequiredArgsConstructor; import javax.servlet.http.HttpServletResponse; import javax.validation.constraints.*; @@ -99,27 +100,45 @@ public class WmsBatchController extends BaseController { } - /** - * 检测任务执行是否会产生死锁 - * - * @param rows 任务执行顺序数组 - * @return 是否存在死锁 - */ - @PostMapping("/check") - public R checkDeadlock(@RequestBody List>> rows) { - boolean hasDeadlock = iWmsBatchService.checkDeadlock(rows); - return R.ok(hasDeadlock); - } /** * 生成不会产生死锁的批次分配方案 + * 相同processId的任务会合并到一个批次组中 + * 不同processId的任务会放在不同的批次组中 * * @param rows 任务执行顺序数组 * @return 批次分配方案 */ @PostMapping("/generate") - public R> generateNonDeadlockBatches(@RequestBody List>> rows) { - List batches = iWmsBatchService.generateNonDeadlockBatches(rows); - return R.ok(batches); + public R> generateNonDeadlockBatches(@RequestBody List>> rows) { + // 先获取原始的批次分配方案 + List originalBatches = iWmsBatchService.generateNonDeadlockBatches(rows); + + // 使用Java 8 Stream API按processId分组并合并任务 + Map> groupedByProcessId = originalBatches.stream() + .collect(java.util.stream.Collectors.groupingBy(BatchGroupVo::getProcessId)); + + // 合并相同processId的批次组 + List mergedBatches = new java.util.ArrayList<>(); + java.util.concurrent.atomic.AtomicInteger groupCounter = new java.util.concurrent.atomic.AtomicInteger(1); + + groupedByProcessId.forEach((processId, groups) -> { + // 创建一个新的合并后的批次组 + BatchGroupVo mergedGroup = new BatchGroupVo(); + mergedGroup.setGroupId("Merged-Group-" + groupCounter.getAndIncrement()); + mergedGroup.setProcessId(processId); + + // 合并所有taskIds + List allTaskIds = groups.stream() + .flatMap(group -> group.getTaskIds().stream()) + .collect(java.util.stream.Collectors.toList()); + mergedGroup.setTaskIds(allTaskIds); + + mergedBatches.add(mergedGroup); + }); + + return R.ok(mergedBatches); } + + } diff --git a/klp-wms/src/main/java/com/klp/domain/vo/BatchGroupVo.java b/klp-wms/src/main/java/com/klp/domain/vo/BatchGroupVo.java new file mode 100644 index 00000000..e93dae7c --- /dev/null +++ b/klp-wms/src/main/java/com/klp/domain/vo/BatchGroupVo.java @@ -0,0 +1,34 @@ +package com.klp.domain.vo; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.List; + +/** + * 批次分组视图对象 + * + * @author CodeBuddy + * @date 2025-08-14 + */ +@Data +@NoArgsConstructor +@AllArgsConstructor +public class BatchGroupVo { + + /** + * 批次组ID + */ + private String groupId; + + /** + * 工艺ID + */ + private String processId; + + /** + * 批次中的任务ID列表 + */ + private List taskIds; +} \ No newline at end of file diff --git a/klp-wms/src/main/java/com/klp/service/IWmsBatchService.java b/klp-wms/src/main/java/com/klp/service/IWmsBatchService.java index 42aa18c3..919fd0ce 100644 --- a/klp-wms/src/main/java/com/klp/service/IWmsBatchService.java +++ b/klp-wms/src/main/java/com/klp/service/IWmsBatchService.java @@ -1,5 +1,6 @@ package com.klp.service; +import com.klp.domain.vo.BatchGroupVo; import com.klp.domain.vo.WmsBatchVo; import com.klp.domain.bo.WmsBatchBo; import com.klp.common.core.page.TableDataInfo; @@ -48,19 +49,11 @@ public interface IWmsBatchService { Boolean deleteWithValidByIds(Collection ids, Boolean isValid); - /** - * 检测任务执行是否会产生死锁 - * - * @param rows 任务执行顺序数组 - * @return 是否存在死锁 - */ - boolean checkDeadlock(List>> rows); - /** * 生成不会产生死锁的批次分配方案 * * @param rows 任务执行顺序数组 * @return 批次分配方案 */ - List generateNonDeadlockBatches(List>> rows); + List generateNonDeadlockBatches(List>> rows); } diff --git a/klp-wms/src/main/java/com/klp/service/impl/WmsBatchServiceImpl.java b/klp-wms/src/main/java/com/klp/service/impl/WmsBatchServiceImpl.java index 5caa9fa0..2d2b803c 100644 --- a/klp-wms/src/main/java/com/klp/service/impl/WmsBatchServiceImpl.java +++ b/klp-wms/src/main/java/com/klp/service/impl/WmsBatchServiceImpl.java @@ -10,6 +10,7 @@ import com.klp.common.utils.StringUtils; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; import com.klp.domain.bo.WmsBatchBo; +import com.klp.domain.vo.BatchGroupVo; import com.klp.domain.vo.WmsBatchVo; import com.klp.domain.WmsBatch; import com.klp.mapper.WmsBatchMapper; @@ -115,32 +116,16 @@ public class WmsBatchServiceImpl implements IWmsBatchService { return baseMapper.deleteBatchIds(ids) > 0; } - /** - * 检测任务执行是否会产生死锁 - * - * @param rows 任务执行顺序数组 - * @return 是否存在死锁 - */ - @Override - public boolean checkDeadlock(List>> rows) { - // 保存任务执行顺序数组 - this.rows = rows; - - // 构建进程依赖图 - Map> graph = buildDependencyGraph(rows); - - // 检测是否存在环(死锁) - return hasCycle(graph); - } - /** * 生成不会产生死锁的批次分配方案 + * 相同processId的任务会合并到一个批次组中 + * 不同processId的任务会放在不同的批次组中 * * @param rows 任务执行顺序数组 * @return 批次分配方案 */ @Override - public List generateNonDeadlockBatches(List>> rows) { + public List generateNonDeadlockBatches(List>> rows) { // 保存任务执行顺序数组 this.rows = rows; @@ -152,83 +137,46 @@ public class WmsBatchServiceImpl implements IWmsBatchService { } } - // 构建进程依赖图 - Map> processGraph = buildProcessDependencyGraph(rows); +// // 构建进程依赖图 +// Map> processGraph = buildProcessDependencyGraph(rows); // 构建任务依赖图 Map> taskGraph = buildTaskDependencyGraph(rows); - // 使用拓扑排序找出可行的批次分配方案 - List> batches = topologicalSort(processGraph, taskGraph, allTasks); - - // 将批次转换为字符串格式 - return batches.stream() - .map(batch -> String.join(",", batch)) - .collect(Collectors.toList()); - } - - /** - * 构建依赖图 - * 如果进程A的任务必须在进程B的任务之前执行,则B依赖于A - */ - private Map> buildDependencyGraph(List>> rows) { - Map> graph = new HashMap<>(); - Map processSequence = new HashMap<>(); - - // 遍历每一行,记录每个进程在每一行的执行顺序 + // 获取任务与进程的映射关系 + Map taskToProcess = new HashMap<>(); + // 获取任务详细信息 + Map> taskDetails = new HashMap<>(); for (List> row : rows) { - // 按sequare排序 - row.sort(Comparator.comparingInt(task -> Integer.parseInt(task.get("sequence").toString()))); - - // 记录每个进程的执行顺序 - for (int i = 0; i < row.size(); i++) { - Map task = row.get(i); + for (Map task : row) { + String taskId = task.get("taskId").toString(); String processId = task.get("processId").toString(); - - // 如果当前进程已经有更早的执行顺序,则保留更早的顺序 - processSequence.putIfAbsent(processId, i); - processSequence.put(processId, Math.min(processSequence.get(processId), i)); - } - - // 构建依赖关系 - for (int i = 0; i < row.size() - 1; i++) { - String currentProcess = row.get(i).get("processId").toString(); - String nextProcess = row.get(i + 1).get("processId").toString(); - - // 添加依赖:nextProcess依赖于currentProcess - graph.putIfAbsent(nextProcess, new HashSet<>()); - graph.get(nextProcess).add(currentProcess); + taskToProcess.put(taskId, processId); + taskDetails.put(taskId, task); } } - return graph; - } + // 使用拓扑排序找出可行的批次分配方案 + List> batchGroups = generateBatchGroups(taskGraph, allTasks, taskToProcess); - /** - * 构建进程依赖图 - */ - private Map> buildProcessDependencyGraph(List>> rows) { - Map> graph = new HashMap<>(); - - // 遍历每一行,记录进程间的依赖关系 - for (List> row : rows) { - // 按sequare排序 - row.sort(Comparator.comparingInt(task -> Integer.parseInt(task.get("sequence").toString()))); - - // 构建依赖关系 - for (int i = 0; i < row.size() - 1; i++) { - String currentProcess = row.get(i).get("processId").toString(); - String nextProcess = row.get(i + 1).get("processId").toString(); - - // 添加依赖:nextProcess依赖于currentProcess - graph.putIfAbsent(nextProcess, new HashSet<>()); - graph.get(nextProcess).add(currentProcess); + // 将批次转换为BatchGroupVo格式 + List result = new ArrayList<>(); + int groupId = 1; + for (List group : batchGroups) { + if (!group.isEmpty()) { + String processId = taskToProcess.get(group.get(0)); + BatchGroupVo batchGroup = new BatchGroupVo(); + batchGroup.setGroupId("Group-" + groupId++); + batchGroup.setProcessId(processId); + batchGroup.setTaskIds(group); + result.add(batchGroup); } } - return graph; + return result; } + /** * 构建任务依赖图 */ @@ -254,29 +202,6 @@ public class WmsBatchServiceImpl implements IWmsBatchService { return graph; } - /** - * 检测图中是否存在环(死锁) - */ - private boolean hasCycle(Map> graph) { - // 所有节点的状态:0=未访问,1=访问中,2=已访问 - Map visited = new HashMap<>(); - - // 初始化所有节点为未访问 - for (String node : graph.keySet()) { - visited.put(node, 0); - } - - // 对每个未访问的节点进行DFS - for (String node : graph.keySet()) { - if (visited.get(node) == 0) { - if (hasCycleDFS(node, graph, visited)) { - return true; - } - } - } - - return false; - } /** * DFS检测环 @@ -308,20 +233,12 @@ public class WmsBatchServiceImpl implements IWmsBatchService { } /** - * 使用拓扑排序生成批次分配方案 - * 确保相同processId的任务才能合并到同一个批次 + * 生成批次分组 + * 相同processId的任务会合并到一个列表中 + * 不同processId的任务会放在不同的列表中 */ - private List> topologicalSort(Map> processGraph, Map> taskGraph, Set allTasks) { - // 获取任务与进程的映射关系 - Map taskToProcess = new HashMap<>(); - for (List> row : rows) { - for (Map task : row) { - String taskId = task.get("taskId").toString(); - String processId = task.get("processId").toString(); - taskToProcess.put(taskId, processId); - } - } - + private List> generateBatchGroups( Map> taskGraph, + Set allTasks, Map taskToProcess) { // 计算每个任务的入度 Map inDegree = new HashMap<>(); for (String task : allTasks) { @@ -342,23 +259,27 @@ public class WmsBatchServiceImpl implements IWmsBatchService { } } - // 存储批次分配方案 - List> batches = new ArrayList<>(); + // 存储批次分组方案 + List> batchGroups = new ArrayList<>(); + + // 记录已经分配到批次的进程ID + Set processedProcessIds = new HashSet<>(); // 进行拓扑排序 while (!queue.isEmpty()) { - // 按进程ID分组的当前批次任务 - Map> processBatches = new HashMap<>(); - - // 处理当前队列中的所有任务(这些任务可以并行执行) + // 当前层级可以并行执行的任务 + List currentLevelTasks = new ArrayList<>(); int size = queue.size(); - for (int i = 0; i < size; i++) { - String task = queue.poll(); - String processId = taskToProcess.get(task); - // 按进程ID分组 - processBatches.putIfAbsent(processId, new HashSet<>()); - processBatches.get(processId).add(task); + for (int i = 0; i < size; i++) { + currentLevelTasks.add(queue.poll()); + } + + // 按进程ID分组 + Map> processBatches = new HashMap<>(); + for (String task : currentLevelTasks) { + String processId = taskToProcess.get(task); + processBatches.computeIfAbsent(processId, k -> new ArrayList<>()).add(task); // 更新依赖于当前任务的任务的入度 for (Map.Entry> entry : taskGraph.entrySet()) { @@ -377,15 +298,48 @@ public class WmsBatchServiceImpl implements IWmsBatchService { } // 将每个进程的任务作为一个批次添加 - for (Set batch : processBatches.values()) { - if (!batch.isEmpty()) { - batches.add(batch); + for (Map.Entry> entry : processBatches.entrySet()) { + String processId = entry.getKey(); + List tasks = entry.getValue(); + + if (!tasks.isEmpty()) { + // 检查该进程是否已经有批次 + boolean merged = false; + + // 如果该进程ID已经处理过,则不能再合并 + if (processedProcessIds.contains(processId)) { + batchGroups.add(tasks); + } else { + // 尝试合并到现有批次 + for (List existingBatch : batchGroups) { + // 获取批次中第一个任务的进程ID + if (!existingBatch.isEmpty()) { + String existingProcessId = taskToProcess.get(existingBatch.get(0)); + + // 如果进程ID相同,则合并 + if (processId.equals(existingProcessId)) { + existingBatch.addAll(tasks); + merged = true; + break; + } + } + } + + // 如果没有合并到现有批次,则创建新批次 + if (!merged) { + batchGroups.add(tasks); + } + + // 标记该进程ID已处理 + processedProcessIds.add(processId); + } } } } - return batches; + return batchGroups; } + }