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.Agv;
|
import com.zy.acs.manager.manager.entity.AgvDetail;
|
import com.zy.acs.manager.manager.entity.Guarantee;
|
import com.zy.acs.manager.manager.entity.Task;
|
import com.zy.acs.manager.manager.enums.StatusType;
|
import com.zy.acs.manager.manager.enums.TaskStsType;
|
import com.zy.acs.manager.manager.enums.TaskTypeType;
|
import com.zy.acs.manager.manager.service.AgvDetailService;
|
import com.zy.acs.manager.manager.service.AgvService;
|
import com.zy.acs.manager.manager.service.TaskService;
|
import lombok.extern.slf4j.Slf4j;
|
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 {
|
|
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() == null ? 50 : plan.getMinSoc();
|
List<Agv> scopedAgvs = findScopedAgvs(plan);
|
int available = 0;
|
List<ChargeCandidate> candidates = new ArrayList<>();
|
for (Agv agv : scopedAgvs) {
|
AgvDetail detail = agvDetailService.selectByAgvId(agv.getId());
|
if (detail == null || detail.getSoc() == null) {
|
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;
|
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;
|
}
|
long busyCount = taskService.count(new LambdaQueryWrapper<Task>()
|
.eq(Task::getAgvId, agv.getId())
|
.in(Task::getTaskSts,
|
TaskStsType.WAITING.val(),
|
TaskStsType.ASSIGN.val(),
|
TaskStsType.PROGRESS.val()));
|
return busyCount == 0;
|
}
|
|
private List<Agv> findScopedAgvs(Guarantee plan) {
|
LambdaQueryWrapper<Agv> wrapper = new LambdaQueryWrapper<Agv>()
|
.eq(Agv::getStatus, StatusType.ENABLE.val);
|
if ("MODEL".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);
|
}
|
|
private static class ChargeCandidate {
|
private final Agv agv;
|
private final int soc;
|
|
ChargeCandidate(Agv agv, int soc) {
|
this.agv = agv;
|
this.soc = soc;
|
}
|
|
public Agv getAgv() {
|
return agv;
|
}
|
|
public int getSoc() {
|
return soc;
|
}
|
}
|
}
|