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