1. 分配工作逻辑修改

This commit is contained in:
梁州 2025-05-06 16:35:05 +08:00
parent 5e095d8f74
commit 7a3090d752
4 changed files with 227 additions and 459 deletions

View File

@ -1,234 +0,0 @@
package com.wms.controller;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.wms.constants.enums.ConfigMapKeyEnum;
import com.wms.entity.table.Stand;
import com.wms.service.*;
import com.wms.service.business.IWmsJobService;
import com.wms.service.business.IWorkService;
import com.wms.utils.StringUtils;
import lombok.RequiredArgsConstructor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.interceptor.TransactionAspectSupport;
import static com.wms.config.InitLocalConfig.configMap;
import static com.wms.utils.StringUtils.convertJsonString;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.util.*;
/**
* 定期任务类
*/
@Component
@RequiredArgsConstructor(onConstructor = @__(@Autowired))
public class JobComponent {
private final Logger logger = LoggerFactory.getLogger(this.getClass());
/**
* WMS定时任务服务
*/
private final IWmsJobService wmsJobService;
/**
* 站台服务
*/
private final StandService standService;
/**
* 工作服务
*/
private final IWorkService workService;
private boolean isSendingCommonTask = false;
private boolean isSendingPickOutTask = false;
private boolean isSendingPickTask = false;
/**
* 向Wcs下发任务
* 每2秒执行一次
*/
// @Scheduled(fixedDelay = 2000)
@Transactional(isolation = Isolation.REPEATABLE_READ, propagation = Propagation.REQUIRED)
public void sendCommonTasks() {
if (isSendingCommonTask) {
// 正在执行下发任务操作
return;
} else {
isSendingCommonTask = true;
}
try {
String sendTask = configMap.get(ConfigMapKeyEnum.SEND_TASK.getConfigKey());
if (StringUtils.isEmpty(sendTask) || !sendTask.equals("1")) {
return;
}
// 发送正常任务
wmsJobService.sendCommonTasks();
} catch (Exception e) {
// 回滚事务
TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
} finally {
isSendingCommonTask = false;
}
}
/**
* 向Wcs下发站台拣选出库任务
* 每2秒执行一次
*/
// @Scheduled(fixedDelay = 2000)
@Transactional(isolation = Isolation.REPEATABLE_READ, propagation = Propagation.REQUIRED)
public void sendPickOutTasks() {
if (isSendingPickOutTask) {
return;
} else {
isSendingPickOutTask = true;
}
try {
String sendTask = configMap.get(ConfigMapKeyEnum.SEND_PICK_OUT_TASK.getConfigKey());
if (StringUtils.isEmpty(sendTask) || !sendTask.equals("1")) {
return;
}
// 发送站台拣选出库任务
wmsJobService.sendPickOutTasks();
} catch (Exception e) {
// 回滚事务
TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
} finally {
isSendingPickOutTask = false;
}
}
/**
* 拣选任务
* 每2秒执行一次
*/
// @Scheduled(fixedDelay = 2000)
@Transactional(isolation = Isolation.REPEATABLE_READ, propagation = Propagation.REQUIRED)
public void sendPickTasks() {
if (isSendingPickTask) {
return;
} else {
isSendingPickTask = true;
}
try {
String sendTask = configMap.get(ConfigMapKeyEnum.SEND_TASK.getConfigKey());
if (StringUtils.isEmpty(sendTask) || !sendTask.equals("1")) {
return;
}
// 发送拣选任务
wmsJobService.sendPickTasks();
} catch (Exception e) {
// 回滚事务
TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
} finally {
isSendingPickTask = false;
}
}
/**
* 重复入库任务
* 每2秒执行一次
*/
// @Scheduled(fixedDelay = 2000)
// @Async("myThreadPool")
@Transactional(isolation = Isolation.REPEATABLE_READ, propagation = Propagation.REQUIRED)
public void solveDuplicateTask() {
String sendTask = configMap.get(ConfigMapKeyEnum.SEND_TASK.getConfigKey());
if (StringUtils.isEmpty(sendTask) || !sendTask.equals("1")) {
return;
}
try {
// 针对重复入库的任务发送新的目的地
wmsJobService.solveDuplicateTask();
} catch (Exception e) {
// 回滚事务
TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
}
}
/**
* 创建工作
*/
// @Scheduled(fixedDelay = 20000)
public void createWork() {
String createWork = configMap.get(ConfigMapKeyEnum.CREATE_WORK.getConfigKey());
if (StringUtils.isEmpty(createWork) || !createWork.equals("1")) {
return;
}
// 判断当前时间是否在740到2340之间
LocalDateTime now = LocalDateTime.now();
if (now.isBefore(LocalDateTime.of(now.toLocalDate(), LocalTime.of(7, 40))) || now.isAfter(LocalDateTime.of(now.toLocalDate(), LocalTime.of(23, 40)))) {
return;
}
try {
workService.createTempWorkFlows();
} catch (Exception e) {
logger.error("创建当日工作发生错误:{}", e.getMessage());
}
// 轮询工作站台判断是否需要下发任务
List<Stand> stands = standService.list(new LambdaQueryWrapper<Stand>()
.eq(Stand::getIsLock, 0).eq(Stand::getStandStatus, 0)
.eq(Stand::getStandType, 2).orderByAsc(Stand::getStandId));
for (Stand workStation : stands) {
try {
// 创建工作
// workService.createWork(workStation.getStandId());
// 分配工作
workService.distributeWorks(workStation.getStandId());
} catch (Exception e) {
// logger.error("创建工作时发生错误:{}", e.getMessage());
logger.error("分配工作时发生错误:{}", e.getMessage());
}
}
}
/**
* 执行工作
*/
// @Scheduled(fixedDelay = 20000)
public void doWork() {
String startWork = configMap.get(ConfigMapKeyEnum.START_WORK.getConfigKey());
if (StringUtils.isEmpty(startWork) || !startWork.equals("1")) {
return;
}
// 轮询工作站台判断是否需要下发任务
List<Stand> stands = standService.list(new LambdaQueryWrapper<Stand>()
.eq(Stand::getIsLock, 0).eq(Stand::getStandStatus, 0)
.eq(Stand::getStandType, 2));
List<String> standIds = stands.stream().map(Stand::getStandId).toList();
for (String standId : standIds) {
try {
workService.doWork(standId);
} catch (Exception e) {
logger.error("执行工作时发生错误:{}", convertJsonString(e.getMessage()));
}
}
// try {
// // 执行工作
// workService.doWorkNew(standIds);
// } catch (Exception e) {
// logger.error("执行工作时发生错误:{}", convertJsonString(e.getMessage()));
// }
}
/**
* 每天查询一次是否有过期记录
* 每天晚上10点执行一次
*/
// @Scheduled(cron = "0 0 22 * * ?")
public void deleteOutOfDateData() {
// 删除日志数据
wmsJobService.deleteLogsRegularly();
// 删除记录数据
wmsJobService.deleteRecordsRegularly();
}
}

View File

@ -65,17 +65,11 @@ public class KateWorkExecutor implements Job {
} catch (Exception e) { } catch (Exception e) {
log.error("创建当日工作发生错误:{}", e.getMessage()); log.error("创建当日工作发生错误:{}", e.getMessage());
} }
// 轮询工作站台判断是否需要下发任务 try {
List<Stand> stands = standService.list(new LambdaQueryWrapper<Stand>() // 分配工作
.eq(Stand::getIsLock, 0).eq(Stand::getStandStatus, 0) workService.distributeWorks();
.eq(Stand::getStandType, 2).orderByAsc(Stand::getStandId)); } catch (Exception e) {
for (Stand workStation : stands) { log.error("分配工作时发生错误:{}", e.getMessage());
try {
// 分配工作
workService.distributeWorks(workStation.getStandId());
} catch (Exception e) {
log.error("分配工作时发生错误:{}", e.getMessage());
}
} }
} }

View File

@ -21,14 +21,11 @@ public interface IWorkService {
/** /**
* 创建暂存工作 * 创建暂存工作
* @throws Exception 异常
*/ */
void createTempWorkFlows() throws Exception; void createTempWorkFlows();
/** /**
* 分配工作 * 分配工作
* @param workStation 站台号
* @throws Exception 异常
*/ */
void distributeWorks(String workStation) throws Exception; void distributeWorks();
} }

View File

@ -10,7 +10,6 @@ import com.wms.service.*;
import com.wms.service.business.IWmsTaskService; import com.wms.service.business.IWmsTaskService;
import com.wms.service.business.IWorkService; import com.wms.service.business.IWorkService;
import com.wms.utils.StringUtils; import com.wms.utils.StringUtils;
import com.wms.utils.WmsUtils;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
@ -26,7 +25,6 @@ import java.time.LocalDate;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.util.*; import java.util.*;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import java.util.stream.Stream;
import static com.wms.config.InitLocalConfig.*; import static com.wms.config.InitLocalConfig.*;
import static com.wms.constants.WmsConstants.MYSQL_JSON_CI; import static com.wms.constants.WmsConstants.MYSQL_JSON_CI;
@ -458,7 +456,7 @@ public class WorkServiceImplements implements IWorkService {
for (KateOrders tempOrder : kateWorkOrderList) { for (KateOrders tempOrder : kateWorkOrderList) {
// 生成workFlow // 生成workFlow
WorkFlow tempWorkFlow = new WorkFlow(); WorkFlow tempWorkFlow = new WorkFlow();
tempWorkFlow.setWorkFlowId(WmsUtils.generateId("WORKFLOW_")); tempWorkFlow.setWorkFlowId(generateId("WORKFLOW_"));
tempWorkFlow.setOrderId(tempOrder.getOrderId()); tempWorkFlow.setOrderId(tempOrder.getOrderId());
tempWorkFlow.setWorkStation(workStation); tempWorkFlow.setWorkStation(workStation);
tempWorkFlow.setWorkOrder(tempOrder.getWorkOrder()); tempWorkFlow.setWorkOrder(tempOrder.getWorkOrder());
@ -567,7 +565,6 @@ public class WorkServiceImplements implements IWorkService {
allFlows.addAll(thisDayMWLWorks); allFlows.addAll(thisDayMWLWorks);
} }
} }
} else { } else {
List<WorkFlow> oldMgWorkFlows = allOldWorkFlows.stream().filter(workFlow -> workFlow.getMachineType() == 2).toList(); List<WorkFlow> oldMgWorkFlows = allOldWorkFlows.stream().filter(workFlow -> workFlow.getMachineType() == 2).toList();
if (oldMgWorkFlows.isEmpty()) { if (oldMgWorkFlows.isEmpty()) {
@ -665,124 +662,102 @@ public class WorkServiceImplements implements IWorkService {
} }
/** /**
* 分配任务 * 分配工作
* * 重构
* @param workStation 站台号
*/ */
@Override @Override
@Transactional(rollbackFor = Exception.class) @Transactional(rollbackFor = Exception.class)
public void distributeWorks(String workStation) { public void distributeWorks() {
if (StringUtils.isEmpty(workStation)) {
// 站台号为空
logger.error("站台号为空===》》》》》》");
return;
}
try { try {
// 查询所有的拣选站台
List<Stand> allPickStands = standService.list(new LambdaQueryWrapper<Stand>()
.eq(Stand::getStandType, 2).eq(Stand::getIsLock, 0)
.orderByAsc(Stand::getStandId));
// 找出可用的站台
List<Stand> usablePickStands = allPickStands.stream().filter(stand -> stand.getStandStatus() == 0).toList();
if (usablePickStands.size() != allPickStands.size()) {
logger.info("站台未全部释放,不执行分配。");
}
// 映射出站台号
List<String> standIds = usablePickStands.stream().map(Stand::getStandId).distinct().toList();
// 查询出所有的工作流
List<WorkFlow> allCurrentWorks = workFlowService.list();
// 查询这些站台是否已经分配了工作
boolean haveDistributedWorks = false;
for (String standId : standIds) {
List<WorkFlow> distributedWorks = allCurrentWorks.stream().filter(workFlow -> workFlow.getWorkStation().equals(standId)).toList();
if (!distributedWorks.isEmpty()) {
haveDistributedWorks = true;
break;
}
}
if (haveDistributedWorks) {
logger.info("有站台进行过分配,不执行分配。");
return;
}
// 获取工作优先级 // 获取工作优先级
String workPriority = configMap.get(ConfigMapKeyEnum.WORK_PRIORITY.getConfigKey()); String workPriority = configMap.get(ConfigMapKeyEnum.WORK_PRIORITY.getConfigKey());
List<WorkFlow> needDistributeWorks = new ArrayList<>(); List<WorkFlow> needDistributeWorks = new ArrayList<>();
List<WorkFlow> commonMwlWorks = workFlowService.list(new LambdaQueryWrapper<>());
int currentWorkType; int currentWorkType;
List<WorkFlow> doingWorks = filterWorkFlow(commonMwlWorks, workStation, 0, -1, -1);
if (!doingWorks.isEmpty()) {
// 当前站台还有正在做的工作不允许再分配新工作
return;
}
if (!StringUtils.isEmpty(workPriority) && workPriority.equals("1")) { if (!StringUtils.isEmpty(workPriority) && workPriority.equals("1")) {
// 当前工作优先级为先平地机后装载机 // 当前工作优先级为先平地机后装载机
List<WorkFlow> oldWorkFlows = filterWorkFlow(commonMwlWorks, null, 2, -1, 0); List<WorkFlow> needDistributeMgWorks = allCurrentWorks.stream().filter(workFlow -> workFlow.getMachineType() == 2 && workFlow.getWorkStatus() == -1).toList();
if (oldWorkFlows.isEmpty()) { if (!needDistributeMgWorks.isEmpty()) {
// 判断下是否有平地机任务还未生成 needDistributeWorks.addAll(needDistributeMgWorks);
List<WorkFlow> notCreatedMGWorks = new ArrayList<>();
findWorks("", notCreatedMGWorks, "NOT_MWL", getCurrentWorkDate());
if (!notCreatedMGWorks.isEmpty()) {
// 仍有未生成的平地机任务跳过
return;
}
//过滤commonMwlWorks 根据machineType=2,workStatus=-1 和workStation=1
List<WorkFlow> doingMgWorkFlows = filterWorkFlow(commonMwlWorks, workStation, 2, -1, -1);
if (!doingMgWorkFlows.isEmpty()) {
// 当前站台平地机正在做
return;
}
// 查询装载机
//过滤commonMwlWorks 根据machineType=1,workStatus=-1
List<WorkFlow> mwlWorks = filterWorkFlow(commonMwlWorks, null, 1, -1, 0);
if (mwlWorks.isEmpty()) {
// 没有装载机任务跳过
return;
}
needDistributeWorks.addAll(mwlWorks);
currentWorkType = 1;// 装载机
} else {
needDistributeWorks.addAll(oldWorkFlows);
currentWorkType = 2;// 平地机 currentWorkType = 2;// 平地机
} else {
List<WorkFlow> needDistributeMwlWorks = allCurrentWorks.stream().filter(workFlow -> workFlow.getMachineType() == 1 && workFlow.getWorkStatus() == -1).toList();
if (!needDistributeMwlWorks.isEmpty()) {
needDistributeWorks.addAll(needDistributeMwlWorks);
currentWorkType = 1;// 装载机
} else {
logger.info("当前没有未分配的工作,优先级:平地机优先。");
return;
}
} }
} else { } else {
// 默认优先级为先装载机后平地机 // 默认优先级为先装载机后平地机
List<WorkFlow> oldWorkFlows = filterWorkFlow(commonMwlWorks, null, 1, -1, 0); List<WorkFlow> needDistributeMwlWorks = allCurrentWorks.stream().filter(workFlow -> workFlow.getMachineType() == 1 && workFlow.getWorkStatus() == -1).toList();
if (oldWorkFlows.isEmpty()) { if (!needDistributeMwlWorks.isEmpty()) {
// 判断下是否有装载机任务还未生成 needDistributeWorks.addAll(needDistributeMwlWorks);
List<WorkFlow> notCreatedMWLWorks = new ArrayList<>();
findWorks("", notCreatedMWLWorks, "MWL", getCurrentWorkDate());
if (!notCreatedMWLWorks.isEmpty()) {
// 仍有未生成的装载机任务跳过
return;
}
List<WorkFlow> doingMwlWorkFlows = filterWorkFlow(commonMwlWorks, workStation, 1, -1, -1);
if (!doingMwlWorkFlows.isEmpty()) {
// 当前站台装载机正在做
return;
}
// 查询平地机
List<WorkFlow> mgWorks = filterWorkFlow(commonMwlWorks, null, 2, -1, 0);
if (mgWorks.isEmpty()) {
// 没有平地机任务跳过
return;
}
needDistributeWorks.addAll(mgWorks);
currentWorkType = 2;// 平地机
} else {
needDistributeWorks.addAll(oldWorkFlows);
currentWorkType = 1;// 装载机 currentWorkType = 1;// 装载机
} else {
List<WorkFlow> needDistributeMgWorks = allCurrentWorks.stream().filter(workFlow -> workFlow.getMachineType() == 2 && workFlow.getWorkStatus() == -1).toList();
if (!needDistributeMgWorks.isEmpty()) {
needDistributeWorks.addAll(needDistributeMgWorks);
currentWorkType = 2;// 平地机
} else {
logger.info("当前没有未分配的工作,优先级:装载机优先。");
return;
}
} }
} }
// 最终需要存储的数据 // 最终需要存储的数据
List<GoodsToStation> finalGoodsToStations;// 物料分配 List<GoodsToStation> finalGoodsToStations = new ArrayList<>();// 物料分配
List<ELocationConfig> finalELocationConfigs = new ArrayList<>();// 标签库位分配 List<ELocationConfig> finalELocationConfigs = new ArrayList<>();// 标签库位分配
// 获取当前站台所有可用的电子标签库位 // 获取所有可用的电子标签位
List<ETagLocation> thisStandELocations = eTagLocationService.list(new LambdaQueryWrapper<ETagLocation>() List<ETagLocation> allELocations = eTagLocationService.list(new LambdaQueryWrapper<ETagLocation>()
.eq(ETagLocation::getWorkStation, workStation)
.eq(ETagLocation::getELocationStatus, 0) .eq(ETagLocation::getELocationStatus, 0)
.orderByAsc(ETagLocation::getSequenceId)); .orderByAsc(ETagLocation::getSequenceId));
// 获取已经添加的电子标签库位分配 // 获取已经添加的电子标签库位分配
List<ELocationConfig> allELocationConfigs = eLocationConfigService.list(); List<ELocationConfig> oldELocationConfigs = eLocationConfigService.list();
// 筛选出剩余可用的电子标签库位 if (oldELocationConfigs != null && !oldELocationConfigs.isEmpty()) {
List<String> usedELocationIds = allELocationConfigs.stream().map(ELocationConfig::getELocationId).distinct().toList(); logger.info("存在旧的标签配置,不执行分配。");
List<String> remainELocationIds = new ArrayList<>();
for (ETagLocation eTagLocation : thisStandELocations) {
if (usedELocationIds.contains(eTagLocation.getELocationId())) {
continue;
}
remainELocationIds.add(eTagLocation.getELocationId());
}
if (remainELocationIds.isEmpty()) {
// 当前站台没有可用电子标签库位分配了跳过
return; return;
} }
// 然后获取大盒子-订单的map
Map<String, List<WorkFlow>> workFlowsByBigBoxMap = new HashMap<>();
// 获取工站配置 // 获取工站配置
LambdaQueryWrapper<WorkStationConfig> wsConfigQueryWrapper = new LambdaQueryWrapper<>(); LambdaQueryWrapper<WorkStationConfig> wsConfigQueryWrapper = new LambdaQueryWrapper<>();
if (currentWorkType == 1) { if (currentWorkType == 1) {
// 当前是装载机工作装载机要区分站台 // 当前是装载机工作装载机要区分站台
wsConfigQueryWrapper.eq(WorkStationConfig::getWorkStation, workStation) wsConfigQueryWrapper
.eq(WorkStationConfig::getModel, "MWL"); .eq(WorkStationConfig::getModel, "MWL");
} else { } else {
// 当前是平地机工作 // 当前是平地机工作
wsConfigQueryWrapper.ne(WorkStationConfig::getModel, "MWL"); wsConfigQueryWrapper.ne(WorkStationConfig::getModel, "MWL");
} }
List<WorkStationConfig> workStationConfigs = workStationConfigService.list(wsConfigQueryWrapper); List<WorkStationConfig> workStationConfigs = workStationConfigService.list(wsConfigQueryWrapper);
// 然后获取大盒子-订单的map
Map<String, List<WorkFlow>> workFlowsByBigBoxMap = new HashMap<>();
// 根据小盒子号生成map // 根据小盒子号生成map
Map<String, String> smallBoxToBigBoxConfigMap = workStationConfigs.stream().collect(Collectors.toMap(WorkStationConfig::getSmallBox, WorkStationConfig::getBigBox)); Map<String, String> smallBoxToBigBoxConfigMap = workStationConfigs.stream().collect(Collectors.toMap(WorkStationConfig::getSmallBox, WorkStationConfig::getBigBox));
for (WorkFlow workFlow : needDistributeWorks) { for (WorkFlow workFlow : needDistributeWorks) {
@ -797,192 +772,228 @@ public class WorkServiceImplements implements IWorkService {
} }
} }
} }
// 根据订单量对大盒子号进行一个排序 // 生成每个大盒子的物料种类map
List<String> bigBoxes = workFlowsByBigBoxMap.keySet().stream().sorted(Comparator.comparingInt(o -> workFlowsByBigBoxMap.get(o).size())).toList(); Map<String, Integer> bigBoxToGoodsTypeQtyMap = new HashMap<>();
// 对已有的大盒子进行一个配置 for (String bigBox : workFlowsByBigBoxMap.keySet()) {
Map<String, String> stationOfBigBoxMap = new HashMap<>(); List<WorkFlow> thisBoxWorkFlows = workFlowsByBigBoxMap.get(bigBox);
// 针对此站台的料盒号工单@工作中心生成一个map int goodsTypeQty = thisBoxWorkFlows.stream().map(WorkFlow::getGoodsId).distinct().toList().size();
Map<String, String> eLocationIdOfBoxMap = new HashMap<>(); bigBoxToGoodsTypeQtyMap.put(bigBox, goodsTypeQty);
for (ELocationConfig oldELocationConfig : allELocationConfigs) {
// 默认大盒子 = 小盒子
String bigBox = oldELocationConfig.getWorkCenter();
if (smallBoxToBigBoxConfigMap.containsKey(oldELocationConfig.getWorkCenter())) {
// 设置为实际的大盒子
bigBox = smallBoxToBigBoxConfigMap.get(oldELocationConfig.getWorkCenter());
}
// 判断这个大盒子是否分配了站台
if (!stationOfBigBoxMap.containsKey(bigBox)) {
stationOfBigBoxMap.put(bigBox, oldELocationConfig.getWorkStation());
}
// 更新料盒号-电子标签库位Map
if (!eLocationIdOfBoxMap.containsKey(oldELocationConfig.getOrderBoxNo())) {
eLocationIdOfBoxMap.put(oldELocationConfig.getOrderBoxNo(), oldELocationConfig.getELocationId());
}
} }
// 开始分配电子标签库位 // 根据物料种类数量对大盒子进行排序
List<WorkFlow> thisTimeDistributeWorkFlows = new ArrayList<>(); List<String> sortedBoxedByGoodsTypeQty = bigBoxToGoodsTypeQtyMap.entrySet().stream().sorted(Map.Entry.comparingByValue(Comparator.reverseOrder())).map(Map.Entry::getKey).toList();
// 每个站台包含的物料种类数量
Map<String, List<String>> stationToGoodsTypeQtyMap = new HashMap<>();
// 每个站台分配的电子标签
Map<String, List<ELocationConfig>> stationToELocationConfigsMap = new HashMap<>();
// 每个站台的物料需求
Map<String, List<GoodsToStation>> stationToGoodsToStationsMap = new HashMap<>();
// 每个站台的剩余电子标签
Map<String, List<String>> stationToRemainELocationMap = new HashMap<>();
for (String standId : standIds) {
List<ETagLocation> thisStandELocations = allELocations.stream().filter(eTagLocation -> eTagLocation.getWorkStation().equals(standId)).toList();
if (thisStandELocations.isEmpty()) {
// 当前站台没有可用电子标签位
stationToRemainELocationMap.put(standId, Collections.emptyList());
continue;
}
// 排序
List<String> thisStandELocationIds = thisStandELocations.stream().sorted(Comparator.comparingInt(ETagLocation::getSequenceId)).map(ETagLocation::getELocationId).toList();
stationToRemainELocationMap.put(standId, thisStandELocationIds);
// 每个站台物料分配种类
stationToGoodsTypeQtyMap.put(standId, new ArrayList<>());
}
// 决定每个大盒子的站台分配
Map<String, String> bigBoxToStandIdMap = new HashMap<>();
// 物料种类总数---这里存在一个分歧大盒子之间的共通物料种类是否需要重复计算---CONFUSION
int totalGoodsTypeQty = needDistributeWorks.stream().map(WorkFlow::getGoodsId).distinct().toList().size();
// 物料种类数量平均值
int goodsTypeQtyAverage = (int) Math.ceil(totalGoodsTypeQty / (double) standIds.size());
// 查询出需要分配的工单的dbs // 查询出需要分配的工单的dbs
List<KateDBS> kateDBSS = kateDBSService.list(new LambdaQueryWrapper<KateDBS>() List<KateDBS> kateDBSS = kateDBSService.list(new LambdaQueryWrapper<KateDBS>()
.in(KateDBS::getWorkOrder, needDistributeWorks.stream().map(WorkFlow::getWorkOrder).distinct().toList())); .in(KateDBS::getWorkOrder, needDistributeWorks.stream().map(WorkFlow::getWorkOrder).distinct().toList()));
// 将这个工单的顺序号进行一个map // 将这个工单的顺序号进行一个map
Map<String, Integer> workOrderToSequenceMap = kateDBSS.stream().collect(Collectors.toMap(KateDBS::getWorkOrder, KateDBS::getWorkSequence)); Map<String, Integer> workOrderToSequenceMap = kateDBSS.stream().collect(Collectors.toMap(KateDBS::getWorkOrder, KateDBS::getWorkSequence));
for (String bigBox : bigBoxes) { for (String bigBox : sortedBoxedByGoodsTypeQty) {
if (remainELocationIds.isEmpty()) { // 找出这个站台下的工作流
// 当前站台没有剩余电子标签位置可以分配了 List<WorkFlow> thisBoxWorkFlows = workFlowsByBigBoxMap.get(bigBox);
break; if (thisBoxWorkFlows.isEmpty()) {
}
// 判断这个大盒子是否分配了站台
if (stationOfBigBoxMap.containsKey(bigBox) && !stationOfBigBoxMap.get(bigBox).equals(workStation)) {
continue;
}
// 获取到这个大盒子下面的所有工作流
List<WorkFlow> thisBigBoxWorks = workFlowsByBigBoxMap.get(bigBox);
if (thisBigBoxWorks.isEmpty()) {
// 当前大盒子没有工作流跳过 // 当前大盒子没有工作流跳过
continue; continue;
} }
// List<WorkFlow> thisBigBoxSortedWorks = thisBigBoxWorks.stream() // 获取这个大盒子下面的物料列表
// .sorted(Comparator.comparing(WorkFlow::getWorkCenter)) List<String> goodsIds = thisBoxWorkFlows.stream().map(WorkFlow::getGoodsId).distinct().toList();
// .sorted(Comparator.comparingInt(workFlow -> workOrderToSequenceMap.get(workFlow.getWorkOrder())))
// .toList();
// 未分配的工作流按照boxNo分组 // 未分配的工作流按照boxNo分组
Map<String, List<WorkFlow>> notDistributeYetWorksByBoxMap = new HashMap<>(); Map<String, List<WorkFlow>> notDistributeYetWorksByBoxMap = new HashMap<>();
for (WorkFlow workFlow : thisBigBoxWorks) { for (WorkFlow workFlow : thisBoxWorkFlows) {
String boxNo = workFlow.getWorkOrder() + "@" + workFlow.getWorkCenter(); String boxNo = workFlow.getWorkOrder() + "@" + workFlow.getWorkCenter();
if (!eLocationIdOfBoxMap.containsKey(boxNo)) { if (notDistributeYetWorksByBoxMap.containsKey(boxNo)) {
if (notDistributeYetWorksByBoxMap.containsKey(boxNo)) { List<WorkFlow> thisBoxNotDistributeYetWorks = new ArrayList<>(notDistributeYetWorksByBoxMap.get(boxNo));
List<WorkFlow> thisBoxNotDistributeYetWorks = new ArrayList<>(notDistributeYetWorksByBoxMap.get(boxNo)); thisBoxNotDistributeYetWorks.add(workFlow);
thisBoxNotDistributeYetWorks.add(workFlow); notDistributeYetWorksByBoxMap.replace(boxNo, thisBoxNotDistributeYetWorks);
notDistributeYetWorksByBoxMap.replace(boxNo, thisBoxNotDistributeYetWorks); } else {
} else { notDistributeYetWorksByBoxMap.put(boxNo, List.of(workFlow));
notDistributeYetWorksByBoxMap.put(boxNo, List.of(workFlow));
}
} }
} }
if (notDistributeYetWorksByBoxMap.isEmpty()) { if (notDistributeYetWorksByBoxMap.isEmpty()) {
// 当前大盒子全部分配完毕 // 当前大盒子全部分配完毕
continue; continue;
} }
// 判断电子标签库位是否足够 String targetStandId = "";
if (notDistributeYetWorksByBoxMap.size() > remainELocationIds.size()) { if (currentWorkType == 1) {
// 这个大盒子的位置不够了整个大盒子都不分配 // 装载机使用固定配置
List<WorkStationConfig> thisBigBoxConfigs = workStationConfigs.stream().filter(workStationConfig -> workStationConfig.getBigBox().equals(bigBox)).toList();
if (!thisBigBoxConfigs.isEmpty()) {
targetStandId = thisBigBoxConfigs.get(0).getWorkStation();
}
} else {
targetStandId = getMinGapStandToAvgAfterAddABox(stationToGoodsTypeQtyMap, goodsIds, goodsTypeQtyAverage, notDistributeYetWorksByBoxMap.size(), stationToRemainELocationMap);
}
if (StringUtils.isEmpty(targetStandId)) {
// 没有站台能够分配
continue; continue;
} }
// 判断这个站台是否还包含剩余标签位
List<String> thisStandRemainELocationIds = new ArrayList<>(stationToRemainELocationMap.get(targetStandId));
if (thisStandRemainELocationIds.size() < notDistributeYetWorksByBoxMap.size()) {
// 标签不够此处的判断主要用于装载机
continue;
}
// 排序后的key
List<String> sortedKeyString = notDistributeYetWorksByBoxMap.keySet().stream() List<String> sortedKeyString = notDistributeYetWorksByBoxMap.keySet().stream()
.sorted(Comparator.comparing(o -> workOrderToSequenceMap.get(o.split("@")[0]))) .sorted(Comparator.comparing(o -> workOrderToSequenceMap.get(o.split("@")[0])))
.sorted(Comparator.comparing(o -> o.split("@")[1])) .sorted(Comparator.comparing(o -> o.split("@")[1]))
.toList(); .toList();
// 本次生成的电子标签配置
List<ELocationConfig> thisStandELocationConfigs = stationToELocationConfigsMap.getOrDefault(targetStandId, new ArrayList<>());
for (String boxNo : sortedKeyString) { for (String boxNo : sortedKeyString) {
if (eLocationIdOfBoxMap.containsKey(boxNo)) {
continue;
}
// 获取一个电子标签库位 // 获取一个电子标签库位
String eLocationId = remainELocationIds.get(0); String eLocationId = thisStandRemainELocationIds.get(0);
ELocationConfig eLocationConfig = new ELocationConfig(); ELocationConfig eLocationConfig = new ELocationConfig();
eLocationConfig.setWorkOrder(boxNo.split("@")[0]); eLocationConfig.setWorkOrder(boxNo.split("@")[0]);
eLocationConfig.setWorkCenter(boxNo.split("@")[1]); eLocationConfig.setWorkCenter(boxNo.split("@")[1]);
eLocationConfig.setWorkStation(workStation); eLocationConfig.setWorkStation(targetStandId);
eLocationConfig.setELocationId(eLocationId); eLocationConfig.setELocationId(eLocationId);
eLocationConfig.setOrderBoxNo(boxNo); eLocationConfig.setOrderBoxNo(boxNo);
// 添加配置 // 添加配置
finalELocationConfigs.add(eLocationConfig); thisStandELocationConfigs.add(eLocationConfig);
eLocationIdOfBoxMap.put(boxNo, eLocationId);
// 添加此次分配列表
thisTimeDistributeWorkFlows.addAll(notDistributeYetWorksByBoxMap.get(boxNo));
// 移除这个库位 // 移除这个库位
remainELocationIds.remove(eLocationId); thisStandRemainELocationIds.remove(eLocationId);
} }
} // 更新电子标签剩余库位
if (thisTimeDistributeWorkFlows.isEmpty()) { stationToRemainELocationMap.replace(targetStandId, thisStandRemainELocationIds);
return; // 更新电子标签配置
stationToELocationConfigsMap.put(targetStandId, thisStandELocationConfigs);
// 已经分配完的大盒子
bigBoxToStandIdMap.put(bigBox, targetStandId);
} }
// 处理分配 // 处理分配
List<GoodsToStation> oldGoodsStations = goodsToStationService.list( List<GoodsToStation> oldGoodsStations = goodsToStationService.list();
new LambdaQueryWrapper<GoodsToStation>().eq(GoodsToStation::getWorkStation, workStation) if (oldGoodsStations != null && !oldGoodsStations.isEmpty()) {
); // 按照站台分组
// 根据料号Map一下 stationToGoodsToStationsMap = oldGoodsStations.stream().collect(Collectors.groupingBy(GoodsToStation::getWorkStation));
Map<String, GoodsToStation> oldGoodsStationsMap = oldGoodsStations.stream().collect(Collectors.toMap(GoodsToStation::getGoodsId, goodsToStation -> goodsToStation)); }
// 新增 // 处理物料的需求分配
Map<String, GoodsToStation> newGoodsToStationMap = new HashMap<>(); List<WorkFlow> thisTimeDistributeWorkFlows = new ArrayList<>();
for (WorkFlow workFlow : thisTimeDistributeWorkFlows) { for (String bigBox : bigBoxToStandIdMap.keySet()) {
if (newGoodsToStationMap.containsKey(workFlow.getGoodsId())) { String thisStandId = bigBoxToStandIdMap.get(bigBox);
// 更新totalNum并把状态改成分配中 // 当前站台的旧的goodsToStation
GoodsToStation goodsToStation = newGoodsToStationMap.get(workFlow.getGoodsId()); List<GoodsToStation> thisStandOldGoodsToStationList = stationToGoodsToStationsMap.getOrDefault(thisStandId, new ArrayList<>());
goodsToStation.setTotalNum(goodsToStation.getTotalNum().add(workFlow.getNeedNum())); // 根据料号Map一下
newGoodsToStationMap.replace(workFlow.getGoodsId(), goodsToStation); Map<String, GoodsToStation> oldGoodsStationsMap = thisStandOldGoodsToStationList.stream().collect(Collectors.toMap(GoodsToStation::getGoodsId, goodsToStation -> goodsToStation));
} else { List<WorkFlow> thisBigBoxWorks = workFlowsByBigBoxMap.get(bigBox);
GoodsToStation newGoodsToStation = new GoodsToStation(); for (WorkFlow workFlow : thisBigBoxWorks) {
if (oldGoodsStationsMap.containsKey(workFlow.getGoodsId())) { if (oldGoodsStationsMap.containsKey(workFlow.getGoodsId())) {
// 以前分配过添加老数据只更新totalNum与状态 // 更新totalNum并把状态改成分配中
newGoodsToStation.setConfigId(oldGoodsStationsMap.get(workFlow.getGoodsId()).getConfigId()); GoodsToStation goodsToStation = oldGoodsStationsMap.get(workFlow.getGoodsId());
newGoodsToStation.setTotalNum(oldGoodsStationsMap.get(workFlow.getGoodsId()).getTotalNum().add(workFlow.getNeedNum())); goodsToStation.setTotalNum(goodsToStation.getTotalNum().add(workFlow.getNeedNum()));
newGoodsToStation.setDistributeStatus(1); oldGoodsStationsMap.replace(workFlow.getGoodsId(), goodsToStation);
} else { } else {
GoodsToStation newGoodsToStation = new GoodsToStation();
newGoodsToStation.setConfigId(generateId("")); newGoodsToStation.setConfigId(generateId(""));
newGoodsToStation.setGoodsId(workFlow.getGoodsId()); newGoodsToStation.setGoodsId(workFlow.getGoodsId());
newGoodsToStation.setWorkStation(workStation); newGoodsToStation.setWorkStation(thisStandId);
newGoodsToStation.setDistributeStatus(0); newGoodsToStation.setDistributeStatus(0);
newGoodsToStation.setDistributedNum(BigDecimal.ZERO); newGoodsToStation.setDistributedNum(BigDecimal.ZERO);
newGoodsToStation.setTotalNum(workFlow.getNeedNum()); newGoodsToStation.setTotalNum(workFlow.getNeedNum());
oldGoodsStationsMap.put(workFlow.getGoodsId(), newGoodsToStation);
} }
newGoodsToStationMap.put(workFlow.getGoodsId(), newGoodsToStation); WorkFlow onlyForUpdateTemp = new WorkFlow();
onlyForUpdateTemp.setWorkFlowId(workFlow.getWorkFlowId());
onlyForUpdateTemp.setWorkStatus(0);
onlyForUpdateTemp.setWorkStation(thisStandId);
thisTimeDistributeWorkFlows.add(onlyForUpdateTemp);
} }
// 替换
stationToGoodsToStationsMap.put(thisStandId, oldGoodsStationsMap.values().stream().toList());
}
// 以下更新物料需求
for (String standId : stationToGoodsToStationsMap.keySet()) {
finalGoodsToStations.addAll(stationToGoodsToStationsMap.get(standId));
} }
finalGoodsToStations = newGoodsToStationMap.values().stream().toList();
// 以下开始更新数据
if (!finalGoodsToStations.isEmpty()) { if (!finalGoodsToStations.isEmpty()) {
goodsToStationService.saveOrUpdateBatch(finalGoodsToStations); goodsToStationService.saveOrUpdateBatch(finalGoodsToStations);
} }
// 添加电子标签库位分配数据 // 以下更新电子标签配置
for (String standId : stationToELocationConfigsMap.keySet()) {
finalELocationConfigs.addAll(stationToELocationConfigsMap.get(standId));
}
if (!finalELocationConfigs.isEmpty()) { if (!finalELocationConfigs.isEmpty()) {
// 添加电子标签库位配置 // 添加电子标签库位配置
eLocationConfigService.saveBatch(finalELocationConfigs); eLocationConfigService.saveBatch(finalELocationConfigs);
} }
// 更新工作流数据 // 更新工作流数据
List<String> flowIds = thisTimeDistributeWorkFlows.stream().map(WorkFlow::getWorkFlowId).toList(); if (!thisTimeDistributeWorkFlows.isEmpty()) {
if (!flowIds.isEmpty()) { workFlowService.updateBatchById(thisTimeDistributeWorkFlows);
workFlowService.update(new LambdaUpdateWrapper<WorkFlow>()
.set(WorkFlow::getWorkStatus, 0)
.set(WorkFlow::getWorkStation, workStation)
.in(WorkFlow::getWorkFlowId, flowIds));
} }
logger.info("分配站台{}工作完成", workStation); logger.info("分配工作完成");
} catch (Exception e) { } catch (Exception e) {
logger.error("分配站台:{}工作发生异常:{}", workStation, convertJsonString(e)); logger.error("分配工作发生异常:{}", convertJsonString(e));
// 回滚事务 // 回滚事务
TransactionAspectSupport.currentTransactionStatus().setRollbackOnly(); TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
} }
} }
/** /**
* 过滤工作流 * 获取最小差距的站台加上新数量后离平均值
* *
* @param workFlows 工作流 * @param goodsIdsToStandMap 目前的每个站台物料种类
* @param workStation 工作站台 * @param goodsIdsThisTime 本次需要增加的物料种类
* @param machineType 机型 * @param avgQty 平均值
* @param workStatus 工作状态 * @param needELocationQty 需要的电子标签数量
* @param flag 0: eq -1:ne * @param stationToRemainELocationMap 站台与剩余电子标签数量
* @return 过滤后的数据 * @return 站台号
*/ */
private List<WorkFlow> filterWorkFlow(List<WorkFlow> workFlows, String workStation, int machineType, int workStatus, int flag) { private String getMinGapStandToAvgAfterAddABox(Map<String, List<String>> goodsIdsToStandMap, List<String> goodsIdsThisTime, int avgQty, int needELocationQty, Map<String, List<String>> stationToRemainELocationMap) {
Stream<WorkFlow> stream = workFlows.stream(); int minGap = Integer.MAX_VALUE;
String targetStandId = "";
if (StringUtils.isNotEmpty(workStation)) { // 这里对站台好排序一下从前到后
stream = stream.filter(workFlow -> workFlow.getWorkStation().equals(workStation)); List<String> sortedStandIds = goodsIdsToStandMap.keySet().stream().sorted(Comparator.comparing(o -> o)).toList();
} // 筛选新增加的物料数量
List<String> thisTimeAddGoodsIds = new ArrayList<>();
if (machineType > 0) { for (String standId : sortedStandIds) {
stream = stream.filter(workFlow -> workFlow.getMachineType().equals(machineType)); if (needELocationQty > stationToRemainELocationMap.get(standId).size()) {
} // 标签个数不够
continue;
if (workStatus != 0) { }
if (flag == 0) { List<String> thisStandGoodsId = goodsIdsToStandMap.get(standId);
stream = stream.filter(workFlow -> workFlow.getWorkStatus().equals(workStatus)); // 筛选新增加的物料数量
} else { List<String> thisTimeAddGoodsIdsOfThisStand = new ArrayList<>();
stream = stream.filter(workFlow -> !workFlow.getWorkStatus().equals(workStatus)); for (String goodsId : goodsIdsThisTime) {
if (thisStandGoodsId.stream().filter(goodsId1 -> goodsId1.equals(goodsId)).toList().isEmpty()) thisTimeAddGoodsIdsOfThisStand.add(goodsId);
}
// 判断偏差值
int gap = thisStandGoodsId.size() + thisTimeAddGoodsIdsOfThisStand.size() - avgQty;
if (gap < minGap) {
minGap = gap;
targetStandId = standId;
thisTimeAddGoodsIds = thisTimeAddGoodsIdsOfThisStand;
} }
} }
if (StringUtils.isNotEmpty(targetStandId)) {
return stream.collect(Collectors.toList()); List<String> thisStandGoodsId = goodsIdsToStandMap.get(targetStandId);
thisStandGoodsId.addAll(thisTimeAddGoodsIds);
goodsIdsToStandMap.put(targetStandId, thisStandGoodsId);
}
return targetStandId;
} }
} }