From 5b238809dea2d47fd10670322977262934055fd9 Mon Sep 17 00:00:00 2001
From: vincentlu <t1341870251@gmail.com>
Date: 星期五, 27 二月 2026 16:10:51 +0800
Subject: [PATCH] #

---
 zy-acs-manager/src/main/java/com/zy/acs/manager/core/service/GuaranteeRuntimeService.java |  147 ++++++++++++++++++++++++++++++++++++++++++-------
 1 files changed, 126 insertions(+), 21 deletions(-)

diff --git a/zy-acs-manager/src/main/java/com/zy/acs/manager/core/service/GuaranteeRuntimeService.java b/zy-acs-manager/src/main/java/com/zy/acs/manager/core/service/GuaranteeRuntimeService.java
index 5c5abec..4d3ca15 100644
--- a/zy-acs-manager/src/main/java/com/zy/acs/manager/core/service/GuaranteeRuntimeService.java
+++ b/zy-acs-manager/src/main/java/com/zy/acs/manager/core/service/GuaranteeRuntimeService.java
@@ -1,32 +1,137 @@
 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.GuaranteeScopeType;
+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;
 
-/**
- * Runtime guarantee orchestration entry.
- */
-public interface GuaranteeRuntimeService {
+@Slf4j
+@Service
+public class GuaranteeRuntimeService {
 
-    /**
-     * Lead time entrance: make sure enough vehicles can reach the target window.
-     */
-    void prepare(Guarantee plan, LocalDateTime targetTime);
+    private final AgvService agvService;
+    private final AgvDetailService agvDetailService;
+    private final TaskService taskService;
+    private final MainLockWrapService mainLockWrapService;
 
-    /**
-     * Lock stage: restrict non-essential dispatching for reserve vehicles.
-     */
-    void lock(Guarantee plan, LocalDateTime targetTime);
+    public GuaranteeRuntimeService(AgvService agvService,
+                                   AgvDetailService agvDetailService,
+                                   TaskService taskService,
+                                   MainLockWrapService mainLockWrapService) {
+        this.agvService = agvService;
+        this.agvDetailService = agvDetailService;
+        this.taskService = taskService;
+        this.mainLockWrapService = mainLockWrapService;
+    }
 
-    /**
-     * Executed repeatedly during the guarantee window to keep SLA.
-     */
-    void checkWindow(Guarantee plan, LocalDateTime targetTime);
+    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<Agv> scopedAgvList = findScopedAgvList(plan);
+        int available = 0;
+        List<ChargeCandidate> candidates = new ArrayList<>();
+        for (Agv agv : scopedAgvList) {
+            AgvDetail detail = agvDetailService.selectMajorByAgvId(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());
+        }
+    }
 
-    /**
-     * Called once after the window ends to release state/records.
-     */
-    void finish(Guarantee plan, LocalDateTime targetTime);
+    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> findScopedAgvList(Guarantee plan) {
+        LambdaQueryWrapper<Agv> wrapper = new LambdaQueryWrapper<Agv>()
+                .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);
+    }
+
+    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;
+        }
+    }
 }
-

--
Gitblit v1.9.1