|
|
|
|
@ -30,9 +30,9 @@ import com.alibaba.fastjson.JSONObject; |
|
|
|
|
import com.baomidou.mybatisplus.core.conditions.Wrapper; |
|
|
|
|
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; |
|
|
|
|
import com.baomidou.mybatisplus.core.metadata.IPage; |
|
|
|
|
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils; |
|
|
|
|
import com.baomidou.mybatisplus.core.toolkit.Wrappers; |
|
|
|
|
import lombok.AllArgsConstructor; |
|
|
|
|
import org.apache.commons.collections4.CollectionUtils; |
|
|
|
|
import org.springblade.common.constant.YieldOrderConst; |
|
|
|
|
import org.springblade.core.mp.base.BaseEntity; |
|
|
|
|
import org.springblade.core.mp.base.BaseServiceImpl; |
|
|
|
|
@ -112,20 +112,22 @@ public class WorkOrderServiceImpl extends BaseServiceImpl<WorkOrderMapper, WorkO |
|
|
|
|
//查询待排产订单,状态是3
|
|
|
|
|
List<YieldOrderEntity> list = yieldOrderService.list(Wrappers.<YieldOrderEntity>lambdaQuery().eq(BaseEntity::getStatus, YieldOrderConst.STATUS_APS)); |
|
|
|
|
if (CollectionUtils.isNotEmpty(list)) { |
|
|
|
|
//校验已排产订单
|
|
|
|
|
checkSchedulingOrder(list); |
|
|
|
|
//初始化人员能力
|
|
|
|
|
List<PersonAbilityEntity> personAbilityEntityList = personAbilityService.list(); |
|
|
|
|
List<PersonAbilityEntity> personAbilityEntityList = personAbilityService.list(Wrappers.<PersonAbilityEntity>lambdaQuery().isNotNull(PersonAbilityEntity::getWorkCenterId).isNotNull(PersonAbilityEntity::getProcessId).isNotNull(PersonAbilityEntity::getCraftId)); |
|
|
|
|
Map<String, PersonAbilityEntity> personAbilityMap = new HashMap<>(); |
|
|
|
|
personAbilityEntityList.forEach(personAbility -> { |
|
|
|
|
personAbilityMap.put(personAbility.getWorkCenterId() + "-" + personAbility.getProcessId() + "-" + personAbility.getCraftId(), personAbility); |
|
|
|
|
}); |
|
|
|
|
//初始化主生产者
|
|
|
|
|
List<MainProducerEntity> mainProducerList = mainProducerService.list(); |
|
|
|
|
List<MainProducerEntity> mainProducerList = mainProducerService.list(Wrappers.<MainProducerEntity>lambdaQuery().isNotNull(MainProducerEntity::getProcessId)); |
|
|
|
|
Map<Long, String> mainProducerMap = new HashMap<>(); |
|
|
|
|
mainProducerList.forEach(item -> { |
|
|
|
|
mainProducerMap.put(item.getProcessId(), item.getMainProducer()); |
|
|
|
|
}); |
|
|
|
|
//计算cr值
|
|
|
|
|
calculateCr(list); |
|
|
|
|
// calculateCr(list);
|
|
|
|
|
//根据作业中心将订单分组,并根据优先级、cr值、订单需求数量、计划下达时间4个维度进行组内排序
|
|
|
|
|
Map<Long, List<YieldOrderEntity>> map = |
|
|
|
|
list.stream() |
|
|
|
|
@ -137,20 +139,22 @@ public class WorkOrderServiceImpl extends BaseServiceImpl<WorkOrderMapper, WorkO |
|
|
|
|
list1 -> { |
|
|
|
|
// 排序逻辑:优先级升序 → CR值降序 → 数量降序 → 时间升序
|
|
|
|
|
list1.sort(Comparator.comparingInt(YieldOrderEntity::getPriorityAps).reversed() |
|
|
|
|
.thenComparing((e1, e2) -> e2.getCrValue().compareTo(e1.getCrValue())) |
|
|
|
|
//.thenComparing((e1, e2) -> e2.getCrValue().compareTo(e1.getCrValue()))
|
|
|
|
|
.thenComparingInt(YieldOrderEntity::getYpQty).reversed() |
|
|
|
|
.thenComparing(YieldOrderEntity::getReleaseDate)); |
|
|
|
|
return list1; |
|
|
|
|
} |
|
|
|
|
) |
|
|
|
|
)); |
|
|
|
|
//处理带有公共前置工序的订单
|
|
|
|
|
Map<String,List<WorkPlanEntity>> planMap = dealCommonCraftOrders(); |
|
|
|
|
//多线程排产
|
|
|
|
|
ExecutorService threadPool = new ThreadPoolExecutor( |
|
|
|
|
map.size(), map.size(), 0L, TimeUnit.MILLISECONDS, |
|
|
|
|
new LinkedBlockingQueue<>(), |
|
|
|
|
r -> new Thread(r, "scheduling-thread-" + System.currentTimeMillis())); |
|
|
|
|
map.forEach((workcenter, orders) -> { |
|
|
|
|
threadPool.execute(() -> allocateResources(orders,personAbilityMap,mainProducerMap)); |
|
|
|
|
threadPool.execute(() -> allocateResources(orders,personAbilityMap,mainProducerMap,planMap)); |
|
|
|
|
}); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
@ -186,6 +190,12 @@ public class WorkOrderServiceImpl extends BaseServiceImpl<WorkOrderMapper, WorkO |
|
|
|
|
mergedDto.setWoCode(woCode); |
|
|
|
|
mergedDto.setProcessName(processName); |
|
|
|
|
for(WorkOrderDto dto : processList){ |
|
|
|
|
mergedDto.setTeamName(dto.getTeamName()); |
|
|
|
|
mergedDto.setCardNo(dto.getCardNo()); |
|
|
|
|
mergedDto.setBatchNo(dto.getBatchNo()); |
|
|
|
|
mergedDto.setPartCode(dto.getPartCode()); |
|
|
|
|
mergedDto.setCurrentProcessName(dto.getCurrentProcessName()); |
|
|
|
|
mergedDto.setMakeQty(dto.getMakeQty()); |
|
|
|
|
if(dto.getPlanStartTime().equals(minStartTime)){ |
|
|
|
|
mergedDto.setStartTime(dto.getStartTime()); |
|
|
|
|
} |
|
|
|
|
@ -194,11 +204,19 @@ public class WorkOrderServiceImpl extends BaseServiceImpl<WorkOrderMapper, WorkO |
|
|
|
|
mergedDto.setPlanStatus(dto.getPlanStatus()); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
//处理跨天的工序
|
|
|
|
|
if(!maxEndTime.substring(0,10).equals(minStartTime.substring(0,10))){ |
|
|
|
|
mergedDto.setEndTime("24:00"); |
|
|
|
|
if(minStartTime.substring(0,10).equals(workOrder.getStartTime())){ |
|
|
|
|
mergedDto.setEndTime("24:00"); |
|
|
|
|
} |
|
|
|
|
if(maxEndTime.substring(0,10).equals(workOrder.getStartTime())){ |
|
|
|
|
mergedDto.setStartTime("0:00"); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
} |
|
|
|
|
mergedDto.setPlanStartTime(minStartTime); |
|
|
|
|
mergedDto.setPlanEndTime(maxEndTime); |
|
|
|
|
|
|
|
|
|
mergedProcessList.add(mergedDto); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
@ -271,6 +289,11 @@ public class WorkOrderServiceImpl extends BaseServiceImpl<WorkOrderMapper, WorkO |
|
|
|
|
workOrderDto.setFactEndTime(maxFactEndTime); |
|
|
|
|
workOrderDto.setTeamName(teamName); |
|
|
|
|
workOrderDto.setOrderStatus(woList.get(0).getOrderStatus()); |
|
|
|
|
workOrderDto.setPartCode(woList.get(0).getPartCode()); |
|
|
|
|
workOrderDto.setBatchNo(woList.get(0).getBatchNo()); |
|
|
|
|
workOrderDto.setCardNo(woList.get(0).getCardNo()); |
|
|
|
|
workOrderDto.setCurrentProcessName(woList.get(0).getCurrentProcessName()); |
|
|
|
|
workOrderDto.setMakeQty(woList.get(0).getMakeQty()); |
|
|
|
|
list1.add(workOrderDto); |
|
|
|
|
} |
|
|
|
|
resultList.put(teamName,list1); |
|
|
|
|
@ -342,6 +365,11 @@ public class WorkOrderServiceImpl extends BaseServiceImpl<WorkOrderMapper, WorkO |
|
|
|
|
workOrderDto.setEndTime(maxEndTime); |
|
|
|
|
workOrderDto.setEquipName(equipName); |
|
|
|
|
workOrderDto.setOrderStatus(woList.get(0).getOrderStatus()); |
|
|
|
|
workOrderDto.setPartCode(woList.get(0).getPartCode()); |
|
|
|
|
workOrderDto.setBatchNo(woList.get(0).getBatchNo()); |
|
|
|
|
workOrderDto.setCardNo(woList.get(0).getCardNo()); |
|
|
|
|
workOrderDto.setCurrentProcessName(woList.get(0).getCurrentProcessName()); |
|
|
|
|
workOrderDto.setMakeQty(woList.get(0).getMakeQty()); |
|
|
|
|
list1.add(workOrderDto); |
|
|
|
|
} |
|
|
|
|
resultList.put(equipName,list1); |
|
|
|
|
@ -393,61 +421,6 @@ public class WorkOrderServiceImpl extends BaseServiceImpl<WorkOrderMapper, WorkO |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* 处理有前置公共工序的分组(WC=镀金大批量,镀金小批量,镀银):轮流每次取指定数量进行资源匹配 |
|
|
|
|
*/ |
|
|
|
|
private void processPublicProcessGroups(Map<String, List<YieldOrderEntity>> groupedMap, int batchSize) { |
|
|
|
|
// 筛选出需要处理的公共工序分组
|
|
|
|
|
List<String> publicProcessWC = Arrays.asList("008", "009", "012"); |
|
|
|
|
Map<String, Iterator<YieldOrderEntity>> wcIterators = new HashMap<>(); |
|
|
|
|
|
|
|
|
|
// 为每个公共工序分组创建迭代器
|
|
|
|
|
for (String wc : publicProcessWC) { |
|
|
|
|
if (groupedMap.containsKey(wc)) { |
|
|
|
|
wcIterators.put(wc, groupedMap.get(wc).iterator()); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
// 转换为List,保证迭代顺序(Map的values()顺序不保证,用List固定顺序)
|
|
|
|
|
List<Iterator<YieldOrderEntity>> iteratorList = wcIterators.values().stream() |
|
|
|
|
.filter(Objects::nonNull) // 过滤null迭代器
|
|
|
|
|
.filter(Iterator::hasNext) // 过滤已耗尽的迭代器
|
|
|
|
|
.collect(Collectors.toList()); |
|
|
|
|
|
|
|
|
|
int batchNumber = 1; |
|
|
|
|
boolean hasMoreElements = true; |
|
|
|
|
|
|
|
|
|
while (hasMoreElements) { |
|
|
|
|
hasMoreElements = false; // 默认无更多元素,后续有元素则置为true
|
|
|
|
|
|
|
|
|
|
// 遍历所有迭代器,逐个轮换处理
|
|
|
|
|
for (int i = 0; i < iteratorList.size(); i++) { |
|
|
|
|
Iterator<YieldOrderEntity> currentIterator = iteratorList.get(i); |
|
|
|
|
List<YieldOrderEntity> currentBatch = new ArrayList<>(batchSize); |
|
|
|
|
|
|
|
|
|
// 从当前迭代器取元素:最多取5个,或取完剩余所有
|
|
|
|
|
int count = 0; |
|
|
|
|
while (currentIterator.hasNext() && count < batchSize) { |
|
|
|
|
currentBatch.add(currentIterator.next()); |
|
|
|
|
count++; |
|
|
|
|
hasMoreElements = true; // 标记有未处理元素
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// 若当前批次有元素,执行资源匹配
|
|
|
|
|
if (!currentBatch.isEmpty()) { |
|
|
|
|
System.out.printf("=== 第%d批资源匹配(迭代器索引:%d,批次大小:%d)===\n", |
|
|
|
|
batchNumber, i, currentBatch.size()); |
|
|
|
|
// allocateResources(currentBatch); // 实际业务处理
|
|
|
|
|
batchNumber++; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// 优化:若当前迭代器已耗尽,从列表中移除(避免后续无效遍历)
|
|
|
|
|
if (!currentIterator.hasNext()) { |
|
|
|
|
iteratorList.remove(i); |
|
|
|
|
i--; // 移除后索引前移,避免跳过下一个迭代器
|
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* TODO:资源匹配,不含超声波水洗 |
|
|
|
|
@ -458,31 +431,57 @@ public class WorkOrderServiceImpl extends BaseServiceImpl<WorkOrderMapper, WorkO |
|
|
|
|
* @since 2025/12/1 18:08 |
|
|
|
|
**/ |
|
|
|
|
@Transactional(rollbackFor = Exception.class) |
|
|
|
|
public void allocateResources(List<YieldOrderEntity> list,Map<String, PersonAbilityEntity> personAbilityMap,Map<Long, String> mainProducerMap) { |
|
|
|
|
public void allocateResources(List<YieldOrderEntity> list,Map<String, PersonAbilityEntity> personAbilityMap,Map<Long, String> mainProducerMap,Map<String,List<WorkPlanEntity>> planMap) { |
|
|
|
|
|
|
|
|
|
for (YieldOrderEntity order : list) { |
|
|
|
|
|
|
|
|
|
//是否可以排产
|
|
|
|
|
Boolean isSchecuding = false; |
|
|
|
|
Boolean isSchecuding = true; |
|
|
|
|
List<WorkPlanEntity> workPlanList = new ArrayList<>(); |
|
|
|
|
//查询所有工序
|
|
|
|
|
List<YieldOrderCraftEntity> craftList = yieldOrderCraftService.list(Wrappers.<YieldOrderCraftEntity>lambdaQuery().eq(YieldOrderCraftEntity::getYoId, order.getId()).orderByAsc(YieldOrderCraftEntity::getProcessNo)); |
|
|
|
|
List<Long> workCenterList = craftList.stream().map(YieldOrderCraftEntity::getWorkCenterId).collect(Collectors.toList()); |
|
|
|
|
//根据作业中心查询所有设备
|
|
|
|
|
List<EquipAbilityEntity> equipAbilityList = equipAbilityService.list(Wrappers.<EquipAbilityEntity>lambdaQuery().in(EquipAbilityEntity::getWorkCenterId, workCenterList)); |
|
|
|
|
Map<Integer,List<EquipAbilityEntity>> equipAbilityMap = equipAbilityList.stream().collect(Collectors.groupingBy(EquipAbilityEntity::getEquipOrder)); |
|
|
|
|
List<Long> workCenterList = craftList.stream().filter(item -> item.getWorkCenterId() != null).map(YieldOrderCraftEntity::getWorkCenterId).collect(Collectors.toList()); |
|
|
|
|
if(workCenterList.size() != craftList.size()){ |
|
|
|
|
order.setErrorInfo("工序信息不完整,含有未匹配作业中心的工序"); |
|
|
|
|
order.setStatus(6); |
|
|
|
|
yieldOrderService.updateById(order); |
|
|
|
|
continue; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
//上一道工序结束时间
|
|
|
|
|
LocalDateTime prevProcessEnd = LocalDateTime.now(); |
|
|
|
|
|
|
|
|
|
//判断是否有公共工序已经处理了,如果有则重新定义workPlanList,获取公共工序的最后结束时间和当前时间做比较,取大的作为上一道工序结束时间
|
|
|
|
|
if(planMap.containsKey(order.getYoCode())){ |
|
|
|
|
workPlanList = planMap.get(order.getYoCode()); |
|
|
|
|
prevProcessEnd = prevProcessEnd.compareTo(workPlanList.get(workPlanList.size()-1).getEndTime()) > 0 ? prevProcessEnd : workPlanList.get(workPlanList.size()-1).getEndTime(); |
|
|
|
|
} |
|
|
|
|
for (int i = 0; i < craftList.size(); i++) { |
|
|
|
|
YieldOrderCraftEntity craft = craftList.get(i); |
|
|
|
|
if ("设备".equals(mainProducerMap.get(craft.getPpsId()))) { |
|
|
|
|
//根据作业中心查询所有设备
|
|
|
|
|
List<EquipAbilityEntity> equipAbilityList = equipAbilityService.list(Wrappers.<EquipAbilityEntity>lambdaQuery().in(EquipAbilityEntity::getWorkCenterId, craft.getWorkCenterId())); |
|
|
|
|
if(CollectionUtils.isEmpty(equipAbilityList)){ |
|
|
|
|
order.setErrorInfo("设备未匹配到对应的设备能力"); |
|
|
|
|
order.setStatus(6); |
|
|
|
|
yieldOrderService.updateById(order); |
|
|
|
|
isSchecuding = false; |
|
|
|
|
break; |
|
|
|
|
} |
|
|
|
|
Map<Integer,List<EquipAbilityEntity>> equipAbilityMap = equipAbilityList.stream().collect(Collectors.groupingBy(EquipAbilityEntity::getEquipOrder)); |
|
|
|
|
|
|
|
|
|
//匹配设备资源
|
|
|
|
|
//获取下一个整数点
|
|
|
|
|
LocalDateTime dateTime = getNextIntegerTime(prevProcessEnd); |
|
|
|
|
for(Map.Entry<Integer,List<EquipAbilityEntity>> entry : equipAbilityMap.entrySet()){ |
|
|
|
|
//根据时间点获取所有设备资源
|
|
|
|
|
List<EquipResourceEntity> equipResourceList = equipResourceService.list(Wrappers.<EquipResourceEntity>lambdaQuery().ge(EquipResourceEntity::getStartTime, dateTime).eq(EquipResourceEntity::getIsUsed, 0).in(EquipResourceEntity::getEquipOrder, entry.getKey())); |
|
|
|
|
List<EquipResourceEntity> equipResourceList = equipResourceService.list(Wrappers.<EquipResourceEntity>lambdaQuery().eq(EquipResourceEntity::getCraftId,craft.getCaId()).eq(EquipResourceEntity::getWorkCenterId,craft.getWorkCenterId()).ge(EquipResourceEntity::getStartTime, dateTime).eq(EquipResourceEntity::getIsUsed, 0).in(EquipResourceEntity::getEquipOrder, entry.getKey())); |
|
|
|
|
if(CollectionUtils.isEmpty(equipResourceList)){ |
|
|
|
|
order.setStatus(6); |
|
|
|
|
order.setErrorInfo("工序:"+craft+"未匹配到对应的设备资源"); |
|
|
|
|
yieldOrderService.updateById(order); |
|
|
|
|
isSchecuding = false; |
|
|
|
|
break; |
|
|
|
|
} |
|
|
|
|
//设备资源按照时间段分组并按时间排序,然后再每个组内按照剩余产能倒序排序
|
|
|
|
|
Map<LocalDateTime, List<EquipResourceEntity>> equipResourceMap = equipResourceList.stream() |
|
|
|
|
.collect(Collectors.groupingBy( |
|
|
|
|
@ -537,6 +536,7 @@ public class WorkOrderServiceImpl extends BaseServiceImpl<WorkOrderMapper, WorkO |
|
|
|
|
workPlan.setHourQuota(BigDecimal.valueOf(ChronoUnit.MINUTES.between(workPlan.getStartTime(), workPlan.getEndTime()))); |
|
|
|
|
workPlan.setEquipCode(equipResource.getEquipCode()); |
|
|
|
|
workPlan.setEquipName(equipResource.getEquipName()); |
|
|
|
|
workPlan.setEquipResourceId(equipResource.getId()); |
|
|
|
|
workPlanList.add(workPlan); |
|
|
|
|
//更新剩余产能
|
|
|
|
|
equipResource.setRestCapacity(equipResource.getRestCapacity().subtract(capacity)); |
|
|
|
|
@ -558,7 +558,6 @@ public class WorkOrderServiceImpl extends BaseServiceImpl<WorkOrderMapper, WorkO |
|
|
|
|
prevProcessEnd = workPlan.getEndTime(); |
|
|
|
|
dateTime = workPlan.getEndTime(); |
|
|
|
|
isOccupied = true; |
|
|
|
|
isSchecuding = true; |
|
|
|
|
break; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
@ -568,15 +567,30 @@ public class WorkOrderServiceImpl extends BaseServiceImpl<WorkOrderMapper, WorkO |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
if(!isSchecuding){ |
|
|
|
|
break; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
} else { |
|
|
|
|
} else if ("人".equals(mainProducerMap.get(craft.getPpsId()))) { |
|
|
|
|
//匹配人资源
|
|
|
|
|
/* String personAbility = craft.getWorkCenterId() + "-" + craft.getPpsId() + "-" + craft.getCaId(); |
|
|
|
|
if (personAbilityMap.containsKey(craft.getWorkCenterId() + "-" + craft.getPpsId() + "-" + craft.getCaId())) { |
|
|
|
|
WorkPlanEntity workPlan = new WorkPlanEntity(); |
|
|
|
|
BigDecimal totalTime = new BigDecimal(0); |
|
|
|
|
totalTime = totalTime.add(BigDecimal.valueOf(order.getYpQty()).multiply(personAbilityMap.get(craft.getWorkCenterId() + "-" + craft.getPpsId() + "-" + craft.getCaId()).getStandardTime()).add(personAbilityMap.get(craft.getWorkCenterId() + "-" + craft.getPpsId() + "-" + craft.getCaId()).getPrepareTime())); |
|
|
|
|
|
|
|
|
|
} else { |
|
|
|
|
order.setStatus(6); |
|
|
|
|
order.setErrorInfo("工序:"+personAbility+"未匹配到对应的人员能力"); |
|
|
|
|
yieldOrderService.updateById(order); |
|
|
|
|
isSchecuding = false; |
|
|
|
|
break; |
|
|
|
|
}*/ |
|
|
|
|
WorkPlanEntity workPlan = new WorkPlanEntity(); |
|
|
|
|
BigDecimal totalTime = new BigDecimal(0); |
|
|
|
|
PersonAbilityEntity ability = personAbilityMap.get(craft.getWorkCenterId() + "-" + craft.getPpsId() + "-" + craft.getCaId()); |
|
|
|
|
//由于客户提供的数据不全,先判断有没有对应的能力,如果没有先不计算时间
|
|
|
|
|
if(ability != null){ |
|
|
|
|
totalTime = totalTime.add(BigDecimal.valueOf(order.getYpQty()).multiply(personAbilityMap.get(craft.getWorkCenterId() + "-" + craft.getPpsId() + "-" + craft.getCaId()).getStandardTime()).add(personAbilityMap.get(craft.getWorkCenterId() + "-" + craft.getPpsId() + "-" + craft.getCaId()).getPrepareTime())); |
|
|
|
|
} |
|
|
|
|
if(totalTime.compareTo(new BigDecimal(0)) > 0){ |
|
|
|
|
//通过加锁的方式保证每次查询到的人力资源都是最新的
|
|
|
|
|
Long craftId = craft.getCaId(); |
|
|
|
|
Lock craftLock = getCraftLock(craftId); |
|
|
|
|
@ -596,11 +610,17 @@ public class WorkOrderServiceImpl extends BaseServiceImpl<WorkOrderMapper, WorkO |
|
|
|
|
if(isUsedIndex != -1){ |
|
|
|
|
personResourceList = personResourceList.subList(isUsedIndex + 1, personResourceList.size()); |
|
|
|
|
} |
|
|
|
|
//如果size=0,说明最近3天的资源都排满了,就不需要排了
|
|
|
|
|
if(personResourceList.size() == 0){ |
|
|
|
|
|
|
|
|
|
break; |
|
|
|
|
} |
|
|
|
|
//计算加工时间占几个人力片段
|
|
|
|
|
int period = totalTime.divide(BigDecimal.valueOf(30),0, RoundingMode.CEILING).intValue(); |
|
|
|
|
//占用时间段
|
|
|
|
|
LocalDateTime startTime = LocalDateTime.now(); |
|
|
|
|
LocalDateTime endTime = LocalDateTime.now(); |
|
|
|
|
StringBuilder personResourceIds = new StringBuilder(); |
|
|
|
|
for(int j=0;j<period;j++){ |
|
|
|
|
|
|
|
|
|
PersonResourceEntity personResource = personResourceList.get(j); |
|
|
|
|
@ -612,48 +632,58 @@ public class WorkOrderServiceImpl extends BaseServiceImpl<WorkOrderMapper, WorkO |
|
|
|
|
} |
|
|
|
|
personResource.setIsUsed("1"); |
|
|
|
|
personResourceService.updateById(personResource); |
|
|
|
|
if(j!=period-1){ |
|
|
|
|
personResourceIds.append(personResource.getId()).append(","); |
|
|
|
|
}else{ |
|
|
|
|
personResourceIds.append(personResource.getId()); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
} |
|
|
|
|
workPlan.setPersonResourceIds(personResourceIds.toString()); |
|
|
|
|
workPlan.setStartTime(startTime); |
|
|
|
|
workPlan.setEndTime(endTime); |
|
|
|
|
workPlan.setMakeTeam(personResourceList.get(0).getTeamId()); |
|
|
|
|
|
|
|
|
|
prevProcessEnd = endTime; |
|
|
|
|
} |
|
|
|
|
}finally { |
|
|
|
|
craftLock.unlock(); // 释放本地锁
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
workPlan.setWoId(order.getId()); |
|
|
|
|
workPlan.setCaId(craft.getCaId()); |
|
|
|
|
workPlan.setPpsId(craft.getPpsId()); |
|
|
|
|
workPlan.setWorkQty(order.getYpQty()); |
|
|
|
|
workPlan.setHourQuota(totalTime); |
|
|
|
|
workPlan.setWorkCenterId(craft.getWorkCenterId()); |
|
|
|
|
workPlan.setOrders(craft.getProcessNo()); |
|
|
|
|
workPlan.setOem("0"); |
|
|
|
|
workPlan.setTestQty(0); |
|
|
|
|
workPlan.setQualifiedQty(0); |
|
|
|
|
workPlan.setUnqualifiedQty(0); |
|
|
|
|
workPlan.setScrapQty(0); |
|
|
|
|
workPlanList.add(workPlan); |
|
|
|
|
} else { |
|
|
|
|
order.setStatus(6); |
|
|
|
|
order.setErrorInfo("未匹配到对应的人员能力"); |
|
|
|
|
|
|
|
|
|
System.out.println("未匹配到对应的人员能力!"); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
workPlan.setWoId(order.getId()); |
|
|
|
|
workPlan.setCaId(craft.getCaId()); |
|
|
|
|
workPlan.setPpsId(craft.getPpsId()); |
|
|
|
|
workPlan.setWorkQty(order.getYpQty()); |
|
|
|
|
workPlan.setHourQuota(totalTime); |
|
|
|
|
workPlan.setWorkCenterId(craft.getWorkCenterId()); |
|
|
|
|
workPlan.setOrders(craft.getProcessNo()); |
|
|
|
|
workPlan.setOem("0"); |
|
|
|
|
workPlan.setTestQty(0); |
|
|
|
|
workPlan.setQualifiedQty(0); |
|
|
|
|
workPlan.setUnqualifiedQty(0); |
|
|
|
|
workPlan.setScrapQty(0); |
|
|
|
|
workPlanList.add(workPlan); |
|
|
|
|
|
|
|
|
|
}else{ |
|
|
|
|
//未匹配到设备和人力资源,将工序状态改为6,标识为未排产
|
|
|
|
|
craft.setStatus(6); |
|
|
|
|
yieldOrderCraftService.updateById(craft); |
|
|
|
|
} |
|
|
|
|
if(!isSchecuding){ |
|
|
|
|
break; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
if(isSchecuding == false){ |
|
|
|
|
workPlanList.clear(); |
|
|
|
|
System.out.println("订单生产量超过设备最大生产量,无法生产"); |
|
|
|
|
if(!isSchecuding){ |
|
|
|
|
continue; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (CollectionUtils.isNotEmpty(workPlanList)) { |
|
|
|
|
//为人员工序赋值开始结束时间
|
|
|
|
|
WorkPlanTimeCalculator(workPlanList); |
|
|
|
|
//新增车间订单和车间计划
|
|
|
|
|
WorkOrderEntity workOrder = new WorkOrderEntity(); |
|
|
|
|
workOrder.setWoCode(order.getYoCode()); |
|
|
|
|
workOrder.setWoCode(this.nextCode(order.getYpCode())); |
|
|
|
|
workOrder.setCardNo(order.getCardNo()); |
|
|
|
|
workOrder.setBatchNo(order.getBatchNo()); |
|
|
|
|
workOrder.setYoId(order.getId()); |
|
|
|
|
@ -673,6 +703,7 @@ public class WorkOrderServiceImpl extends BaseServiceImpl<WorkOrderMapper, WorkO |
|
|
|
|
workOrder.setPushFlag("0"); |
|
|
|
|
workOrder.setQuotaExceptional("0"); |
|
|
|
|
workOrder.setReInStore("0"); |
|
|
|
|
workOrder.setPartCode(order.getPartCode()); |
|
|
|
|
|
|
|
|
|
this.save(workOrder); |
|
|
|
|
workPlanList.forEach(workPlanEntity -> { |
|
|
|
|
@ -854,4 +885,205 @@ public class WorkOrderServiceImpl extends BaseServiceImpl<WorkOrderMapper, WorkO |
|
|
|
|
.map(dt -> dt.format(dateTimeFormatter)) |
|
|
|
|
.orElse(null); |
|
|
|
|
} |
|
|
|
|
public void checkSchedulingOrder(List<YieldOrderEntity> list){ |
|
|
|
|
//判断待排产优先级,1级所有1级往后订单重新排产,2级订单重新排4/5级订单
|
|
|
|
|
List<Integer> priorityList = list.stream().map(YieldOrderEntity::getPriorityAps).collect(Collectors.toList()); |
|
|
|
|
if(priorityList.contains(1)){ |
|
|
|
|
//查询所有非一级的待生产订单
|
|
|
|
|
List<YieldOrderEntity> schedulingOrderList = yieldOrderService.list(Wrappers.<YieldOrderEntity>lambdaQuery().ne(YieldOrderEntity::getPriorityAps,1).eq(YieldOrderEntity::getStatus,4)); |
|
|
|
|
//校验已排产订单资源占用情况
|
|
|
|
|
checkResource(schedulingOrderList); |
|
|
|
|
} |
|
|
|
|
if(priorityList.contains(2)){ |
|
|
|
|
//查询4/5级的待生产订单
|
|
|
|
|
List<YieldOrderEntity> schedulingOrderList = yieldOrderService.list(Wrappers.<YieldOrderEntity>lambdaQuery().in(YieldOrderEntity::getPriorityAps,Arrays.asList("4","5")).eq(YieldOrderEntity::getStatus,4)); |
|
|
|
|
checkResource(schedulingOrderList); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
public void checkResource(List<YieldOrderEntity> list){ |
|
|
|
|
if(CollectionUtils.isNotEmpty(list)){ |
|
|
|
|
//根据订单查询设备资源
|
|
|
|
|
for(YieldOrderEntity yieldOrder : list){ |
|
|
|
|
//查询相关车间订单
|
|
|
|
|
WorkOrderEntity workOrder = this.getOne(Wrappers.<WorkOrderEntity>lambdaQuery().eq(WorkOrderEntity::getYoId,yieldOrder.getId())); |
|
|
|
|
List<WorkPlanEntity> schedulingPlanList = workPlanService.list(Wrappers.<WorkPlanEntity>lambdaQuery().eq(WorkPlanEntity::getWoId,workOrder.getId())); |
|
|
|
|
if(CollectionUtils.isNotEmpty(schedulingPlanList)){ |
|
|
|
|
for(WorkPlanEntity workPlan : schedulingPlanList){ |
|
|
|
|
//还原设备资源
|
|
|
|
|
if(workPlan.getEquipResourceId() != null){ |
|
|
|
|
EquipResourceEntity equipResource = equipResourceService.getById(workPlan.getEquipResourceId()); |
|
|
|
|
equipResource.setIsUsed("0"); |
|
|
|
|
equipResource.setRestCapacity(equipResource.getRestCapacity().add(workPlan.getHourQuota())); |
|
|
|
|
equipResourceService.updateById(equipResource); |
|
|
|
|
|
|
|
|
|
} |
|
|
|
|
//还原人力资源
|
|
|
|
|
if(workPlan.getPersonResourceIds() != null){ |
|
|
|
|
List<PersonResourceEntity> personResourceList = personResourceService.list(Wrappers.<PersonResourceEntity>lambdaQuery().in(BaseEntity::getId,workPlan.getPersonResourceIds().split(","))); |
|
|
|
|
if(CollectionUtils.isNotEmpty(personResourceList)){ |
|
|
|
|
personResourceList.forEach(item ->{ |
|
|
|
|
item.setIsUsed("0"); |
|
|
|
|
personResourceService.updateById(item); |
|
|
|
|
}); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
workPlan.setIsDeleted(1); |
|
|
|
|
workPlanService.updateById(workPlan); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
} |
|
|
|
|
workOrder.setIsDeleted(1); |
|
|
|
|
this.updateById(workOrder); |
|
|
|
|
yieldOrder.setStatus(3); |
|
|
|
|
yieldOrderService.updateById(yieldOrder); |
|
|
|
|
|
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
public List<YieldOrderEntity> sortByWorkcenterIdPer5Group(List<YieldOrderEntity> list) { |
|
|
|
|
|
|
|
|
|
// 按 workcenterId 分组(保留原列表中该 workcenterId 的顺序)
|
|
|
|
|
Map<Long, List<YieldOrderEntity>> groupByWorkcenter = list.stream() |
|
|
|
|
.collect(Collectors.groupingBy( |
|
|
|
|
YieldOrderEntity::getWorkCenterId, |
|
|
|
|
LinkedHashMap::new, // 保留分组的插入顺序(可选,按业务需求)
|
|
|
|
|
Collectors.toList() |
|
|
|
|
)); |
|
|
|
|
|
|
|
|
|
// 对每个分组按每5个拆分批次,记录所有批次
|
|
|
|
|
// key: workcenterId, value: 该workcenterId的批次列表(每个批次最多5个元素)
|
|
|
|
|
Map<Long, List<List<YieldOrderEntity>>> batchMap = new LinkedHashMap<>(); |
|
|
|
|
int maxBatchCount = 0; // 所有分组中最大的批次数量(用于轮询)
|
|
|
|
|
|
|
|
|
|
for (Map.Entry<Long, List<YieldOrderEntity>> entry : groupByWorkcenter.entrySet()) { |
|
|
|
|
Long workCenterId = entry.getKey(); |
|
|
|
|
List<YieldOrderEntity> entityList = entry.getValue(); |
|
|
|
|
|
|
|
|
|
// 拆分批次(每5个一组)
|
|
|
|
|
List<List<YieldOrderEntity>> batches = splitListPer5(entityList); |
|
|
|
|
batchMap.put(workCenterId, batches); |
|
|
|
|
|
|
|
|
|
// 更新最大批次数量
|
|
|
|
|
maxBatchCount = Math.max(maxBatchCount, batches.size()); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// 轮询每个批次,拼接最终列表
|
|
|
|
|
List<YieldOrderEntity> resultList = new ArrayList<>(); |
|
|
|
|
for (int batchIndex = 0; batchIndex < maxBatchCount; batchIndex++) { |
|
|
|
|
// 遍历每个workcenterId,取当前批次的元素
|
|
|
|
|
for (List<List<YieldOrderEntity>> batches : batchMap.values()) { |
|
|
|
|
// 若当前批次存在,则加入结果列表
|
|
|
|
|
if (batchIndex < batches.size()) { |
|
|
|
|
resultList.addAll(batches.get(batchIndex)); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
return resultList; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* 将列表按每5个元素拆分(最后一批可不足5个) |
|
|
|
|
*/ |
|
|
|
|
private List<List<YieldOrderEntity>> splitListPer5(List<YieldOrderEntity> list) { |
|
|
|
|
List<List<YieldOrderEntity>> batches = new ArrayList<>(); |
|
|
|
|
int size = list.size(); |
|
|
|
|
int batchSize = 5; |
|
|
|
|
|
|
|
|
|
for (int i = 0; i < size; i += batchSize) { |
|
|
|
|
int end = Math.min(i + batchSize, size); |
|
|
|
|
batches.add(list.subList(i, end)); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
return batches; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
public Map<String,List<WorkPlanEntity>> dealCommonCraftOrders(){ |
|
|
|
|
List<YieldOrderEntity> commonCraftOrderList = yieldOrderService.selectCommonCraftOrderList(); |
|
|
|
|
Map<String,List<WorkPlanEntity>> planMap = new HashMap<>(); |
|
|
|
|
if(CollectionUtils.isNotEmpty(commonCraftOrderList)){ |
|
|
|
|
//对订单进行排序,每5个相同workCenterId的为一组,实现负载均衡
|
|
|
|
|
commonCraftOrderList = sortByWorkcenterIdPer5Group(commonCraftOrderList); |
|
|
|
|
//对前置公共工序进行排产
|
|
|
|
|
//获取公共工序设备能力,根据工艺能力查询,写死ID是27
|
|
|
|
|
EquipAbilityEntity equipAbility = equipAbilityService.getOne(Wrappers.<EquipAbilityEntity>lambdaQuery().eq(EquipAbilityEntity::getCraftId,27)); |
|
|
|
|
BigDecimal standardProcessAbility = equipAbility.getStandardProcessAbility(); |
|
|
|
|
//获取所有空闲的公共工序资源
|
|
|
|
|
List<EquipResourceEntity> equipResourceList = equipResourceService.selectCommonCraftList(); |
|
|
|
|
for(YieldOrderEntity order : commonCraftOrderList){ |
|
|
|
|
List<WorkPlanEntity> workPlanList = new ArrayList<>(); |
|
|
|
|
//获取相关工序
|
|
|
|
|
YieldOrderCraftEntity craft = yieldOrderCraftService.getOne(Wrappers.<YieldOrderCraftEntity>lambdaQuery().eq(YieldOrderCraftEntity::getYoId,order.getId()).eq(YieldOrderCraftEntity::getCaId,equipAbility.getCraftId())); |
|
|
|
|
//计算订单总产能
|
|
|
|
|
BigDecimal sumCapacity = order.getYpArea().multiply(BigDecimal.valueOf(100)).multiply(BigDecimal.valueOf(order.getYpQty())); |
|
|
|
|
//计算需要占用几个时间段
|
|
|
|
|
int period = sumCapacity.divide(standardProcessAbility,0, RoundingMode.CEILING).intValue(); |
|
|
|
|
|
|
|
|
|
for(int i=0;i<period;i++){ |
|
|
|
|
for(int j=0;j<equipResourceList.size();j++){ |
|
|
|
|
if(i==j){ |
|
|
|
|
EquipResourceEntity equipResource = equipResourceList.get(j); |
|
|
|
|
equipResource.setIsUsed("1"); |
|
|
|
|
equipResourceService.updateById(equipResource); |
|
|
|
|
WorkPlanEntity workPlan = new WorkPlanEntity(); |
|
|
|
|
workPlan.setStartTime(equipResource.getStartTime()); |
|
|
|
|
workPlan.setEndTime(equipResource.getStartTime().plusMinutes(equipResource.getStandardTime().longValue())); |
|
|
|
|
workPlan.setWorkQty(order.getYpQty()); |
|
|
|
|
workPlan.setCaId(craft.getCaId()); |
|
|
|
|
workPlan.setPpsId(craft.getPpsId()); |
|
|
|
|
workPlan.setMakeTeam(equipResource.getTeamId()); |
|
|
|
|
workPlan.setWorkCenterId(craft.getWorkCenterId()); |
|
|
|
|
workPlan.setOrders(craft.getProcessNo()); |
|
|
|
|
workPlan.setWoId(order.getId()); |
|
|
|
|
workPlan.setOem("0"); |
|
|
|
|
workPlan.setTestQty(0); |
|
|
|
|
workPlan.setQualifiedQty(0); |
|
|
|
|
workPlan.setUnqualifiedQty(0); |
|
|
|
|
workPlan.setScrapQty(0); |
|
|
|
|
workPlan.setHourQuota(BigDecimal.valueOf(ChronoUnit.MINUTES.between(workPlan.getStartTime(), workPlan.getEndTime()))); |
|
|
|
|
workPlan.setEquipCode(equipResource.getEquipCode()); |
|
|
|
|
workPlan.setEquipName(equipResource.getEquipName()); |
|
|
|
|
workPlan.setEquipResourceId(equipResource.getId()); |
|
|
|
|
workPlanList.add(workPlan); |
|
|
|
|
break; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
planMap.put(order.getYoCode(),workPlanList); |
|
|
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
} |
|
|
|
|
return planMap; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
public String nextCode(Object obj) { |
|
|
|
|
// 自增总长度
|
|
|
|
|
int len = 3; |
|
|
|
|
// 自增值
|
|
|
|
|
int num = 0; |
|
|
|
|
|
|
|
|
|
// 编码模式
|
|
|
|
|
String codePattern = obj + "-R"; |
|
|
|
|
// 当前模式下最大编码
|
|
|
|
|
String woCode = baseMapper.getMaxByCodePattern(codePattern); |
|
|
|
|
if (woCode != null) { |
|
|
|
|
num = Integer.parseInt(woCode.substring(codePattern.length(), codePattern.length() + len)); |
|
|
|
|
} |
|
|
|
|
num++; |
|
|
|
|
// 下个编码
|
|
|
|
|
return codePattern + prefix(String.valueOf(num), "0", len); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
public static final String prefix(String StringToFix, String fixChar, int targetLen) { |
|
|
|
|
int len = StringToFix.length(); |
|
|
|
|
|
|
|
|
|
for(int i = 0; i < targetLen - len; i += fixChar.length()) { |
|
|
|
|
StringToFix = fixChar + StringToFix; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
return StringToFix; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|