package com.zy.acs.manager.core.service; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.zy.acs.common.enums.AgvStatusType; import com.zy.acs.manager.manager.entity.*; import com.zy.acs.manager.manager.enums.*; import com.zy.acs.manager.manager.service.AgvDetailService; import com.zy.acs.manager.manager.service.AgvService; import com.zy.acs.manager.manager.service.SegmentService; import com.zy.acs.manager.manager.service.TaskService; import lombok.Data; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import java.time.LocalDateTime; import java.util.ArrayList; import java.util.Comparator; import java.util.List; import java.util.Objects; @Slf4j @Service public class GuaranteeRuntimeService { @Autowired private SegmentService segmentService; private final AgvService agvService; private final AgvDetailService agvDetailService; private final TaskService taskService; private final MainLockWrapService mainLockWrapService; public GuaranteeRuntimeService(AgvService agvService, AgvDetailService agvDetailService, TaskService taskService, MainLockWrapService mainLockWrapService) { this.agvService = agvService; this.agvDetailService = agvDetailService; this.taskService = taskService; this.mainLockWrapService = mainLockWrapService; } public void prepare(Guarantee plan, LocalDateTime targetTime) { int requiredCount = plan.getRequiredCount() == null ? 0 : plan.getRequiredCount(); if (requiredCount <= 0) { log.warn("Guarantee[{}] requiredCount is not configured, skip", plan.getName()); return; } int minSoc = plan.getMinSoc(); List scopedAgvList = findScopedAgvList(plan); int available = 0; List candidates = new ArrayList<>(); for (Agv agv : scopedAgvList) { AgvDetail detail = agvDetailService.selectMajorByAgvId(agv.getId()); if (null == detail || null == detail.getSoc() || null == detail.getAgvStatus()) { continue; } if (detail.getAgvStatus().equals(AgvStatusType.CHARGE)) { continue; } if (!isIdle(agv, detail)) { continue; } int soc = detail.getSoc(); if (soc >= minSoc) { available++; } else { candidates.add(new ChargeCandidate(agv, soc)); } } if (available >= requiredCount) { // log.debug("Guarantee[{}] already has {} vehicles >= {}% SOC for {}", plan.getName(), available, minSoc, targetTime); return; } int shortage = requiredCount - available; // 还差多少辆 candidates.sort(Comparator.comparingInt(ChargeCandidate::getSoc)); int scheduled = 0; // 已经安排充电的AGV数量 for (ChargeCandidate candidate : candidates) { if (scheduled >= shortage) { break; } log.info("Guarantee[{}] schedule AGV {} charging (soc={}%) for target {}", plan.getName(), candidate.getAgv().getName(), candidate.getSoc(), targetTime); mainLockWrapService.buildMinorTask(candidate.getAgv().getId(), TaskTypeType.TO_CHARGE, null, null); scheduled++; } if (scheduled < shortage) { log.warn("Guarantee[{}] still short of {} vehicles for {} (only {} idle low-soc AGVs)", plan.getName(), shortage - scheduled, targetTime, candidates.size()); } } private boolean isIdle(Agv agv, AgvDetail detail) { if (!Objects.equals(agv.getStatus(), StatusType.ENABLE.val)) { return false; } if (detail.getAgvStatus() != null && detail.getAgvStatus().equals(AgvStatusType.CHARGE)) { return false; } if (0 < taskService.count(new LambdaQueryWrapper() .eq(Task::getAgvId, agv.getId()) // .and(i -> { // i.eq(Task::getTaskSts, TaskStsType.WAITING.val()) // .or().eq(Task::getTaskSts, TaskStsType.ASSIGN.val()) // .or().eq(Task::getTaskSts, TaskStsType.PROGRESS.val()); // }) .in(Task::getTaskSts, TaskStsType.WAITING.val(), TaskStsType.ASSIGN.val(), TaskStsType.PROGRESS.val()) )) { return false; } if (0 < segmentService.count(new LambdaQueryWrapper() .eq(Segment::getAgvId, agv.getId()) .and( i -> { // i.eq(Segment::getState, SegmentStateType.WAITING.toString()).or() i.eq(Segment::getState, SegmentStateType.RUNNING.toString()); }) )) { return false; } return true; } private List findScopedAgvList(Guarantee plan) { LambdaQueryWrapper wrapper = new LambdaQueryWrapper() .eq(Agv::getStatus, StatusType.ENABLE.val); if (GuaranteeScopeType.MODEL.toString().equalsIgnoreCase(plan.getScopeType()) && plan.getScopeValue() != null) { try { wrapper.eq(Agv::getAgvModel, Long.valueOf(plan.getScopeValue())); } catch (NumberFormatException ignore) { log.warn("Guarantee[{}] invalid scopeValue {}", plan.getName(), plan.getScopeValue()); } } return agvService.list(wrapper); } @Data private static class ChargeCandidate { private final Agv agv; private final int soc; ChargeCandidate(Agv agv, int soc) { this.agv = agv; this.soc = soc; } } }