From 058d7bbb714634e42bff1dd71fdfca3a378421d3 Mon Sep 17 00:00:00 2001
From: Junjie <fallin.jie@qq.com>
Date: 星期二, 31 三月 2026 20:50:50 +0800
Subject: [PATCH] #

---
 src/main/java/com/zy/core/thread/impl/station/StationSegmentExecutor.java     |   40 +++++++++
 src/test/java/com/zy/core/thread/impl/station/StationSegmentPlannerTest.java  |   49 ++++++++++++
 src/test/java/com/zy/common/utils/NavigateUtilsTest.java                      |   49 ++++++++++++
 src/main/java/com/zy/common/utils/NavigateUtils.java                          |    9 +
 src/main/java/com/zy/core/thread/impl/station/StationSegmentPlanner.java      |   19 ++++
 src/test/java/com/zy/core/thread/impl/station/StationSegmentExecutorTest.java |   33 ++++++++
 6 files changed, 195 insertions(+), 4 deletions(-)

diff --git a/src/main/java/com/zy/common/utils/NavigateUtils.java b/src/main/java/com/zy/common/utils/NavigateUtils.java
index ee68fc0..541c143 100644
--- a/src/main/java/com/zy/common/utils/NavigateUtils.java
+++ b/src/main/java/com/zy/common/utils/NavigateUtils.java
@@ -1994,8 +1994,8 @@
     }
 
     private List<NavigateNode> normalizeStationPath(List<NavigateNode> path) {
-        HashSet<Integer> stationIdSet = new HashSet<>();
         List<NavigateNode> filterList = new ArrayList<>();
+        Integer lastStationId = null;
         for (NavigateNode navigateNode : safeList(path)) {
             if (navigateNode == null) {
                 continue;
@@ -2010,9 +2010,14 @@
                 continue;
             }
             Integer stationId = valueObject.getInteger("stationId");
-            if (stationId == null || !stationIdSet.add(stationId)) {
+            if (stationId == null) {
                 continue;
             }
+            // 浠呭帇缂╄繛缁噸澶嶇珯鐐癸紝淇濈暀鐜嚎閲嶇畻鍦烘櫙涓嬪悗缁啀娆$粡杩囩殑鍚屼竴绔欑偣銆�
+            if (lastStationId != null && lastStationId.equals(stationId)) {
+                continue;
+            }
+            lastStationId = stationId;
             NavigateNode clonedNode = navigateNode.clone();
             if (clonedNode == null) {
                 continue;
diff --git a/src/main/java/com/zy/core/thread/impl/station/StationSegmentExecutor.java b/src/main/java/com/zy/core/thread/impl/station/StationSegmentExecutor.java
index eca8680..95209a6 100644
--- a/src/main/java/com/zy/core/thread/impl/station/StationSegmentExecutor.java
+++ b/src/main/java/com/zy/core/thread/impl/station/StationSegmentExecutor.java
@@ -89,6 +89,7 @@
         long lastSeenAt = System.currentTimeMillis();
         int segCursor = 0;
         Integer lastCurrentStationId = null;
+        int lastMatchedPathIndex = -1;
         boolean firstRun = true;
         while (true) {
             try {
@@ -144,12 +145,17 @@
                     break;
                 }
 
-                int currentIndex = effectiveFullPath.indexOf(currentStation.getStationId());
+                int currentIndex = resolveCurrentPathIndex(
+                        effectiveFullPath,
+                        currentStation.getStationId(),
+                        lastMatchedPathIndex
+                );
                 if (currentIndex < 0) {
                     Thread.sleep(500L);
                     firstRun = false;
                     continue;
                 }
+                lastMatchedPathIndex = currentIndex;
 
                 int remaining = effectiveFullPath.size() - currentIndex - 1;
                 if (remaining <= 0) {
@@ -192,6 +198,38 @@
         }
     }
 
+    private int resolveCurrentPathIndex(List<Integer> fullPathStationIds,
+                                        Integer currentStationId,
+                                        int lastMatchedPathIndex) {
+        if (fullPathStationIds == null || fullPathStationIds.isEmpty() || currentStationId == null) {
+            return -1;
+        }
+        if (lastMatchedPathIndex >= 0
+                && lastMatchedPathIndex < fullPathStationIds.size()
+                && equalsInteger(currentStationId, fullPathStationIds.get(lastMatchedPathIndex))) {
+            return lastMatchedPathIndex;
+        }
+
+        int nextIndex = findNextStationIndex(fullPathStationIds, currentStationId, Math.max(lastMatchedPathIndex + 1, 0));
+        if (nextIndex >= 0) {
+            return nextIndex;
+        }
+        return findNextStationIndex(fullPathStationIds, currentStationId, 0);
+    }
+
+    private int findNextStationIndex(List<Integer> path, Integer stationId, int fromIndex) {
+        if (path == null || path.isEmpty() || stationId == null) {
+            return -1;
+        }
+        int startIdx = Math.max(fromIndex, 0);
+        for (int i = startIdx; i < path.size(); i++) {
+            if (equalsInteger(stationId, path.get(i))) {
+                return i;
+            }
+        }
+        return -1;
+    }
+
     private boolean sendSegmentWithRetry(StationCommand command,
                                          StationTaskTraceRegistry traceRegistry,
                                          Integer traceVersion,
diff --git a/src/main/java/com/zy/core/thread/impl/station/StationSegmentPlanner.java b/src/main/java/com/zy/core/thread/impl/station/StationSegmentPlanner.java
index 3c9328c..6d5fba6 100644
--- a/src/main/java/com/zy/core/thread/impl/station/StationSegmentPlanner.java
+++ b/src/main/java/com/zy/core/thread/impl/station/StationSegmentPlanner.java
@@ -34,8 +34,12 @@
         int total = path.size();
         List<Integer> segmentEndIndices = new ArrayList<>();
         if (liftTransferPath != null) {
+            int searchStartIdx = 0;
             for (Integer liftTransferStationId : liftTransferPath) {
-                int endIndex = path.indexOf(liftTransferStationId);
+                int endIndex = findNextStationIndex(path, liftTransferStationId, searchStartIdx);
+                if (endIndex >= 0) {
+                    searchStartIdx = endIndex + 1;
+                }
                 if (endIndex <= 0) {
                     continue;
                 }
@@ -87,6 +91,19 @@
         return plan;
     }
 
+    private int findNextStationIndex(List<Integer> path, Integer stationId, int fromIndex) {
+        if (path == null || path.isEmpty() || stationId == null) {
+            return -1;
+        }
+        int startIdx = Math.max(fromIndex, 0);
+        for (int i = startIdx; i < path.size(); i++) {
+            if (stationId.equals(path.get(i))) {
+                return i;
+            }
+        }
+        return -1;
+    }
+
     private List<Integer> copyIntegerList(List<Integer> source) {
         if (source == null) {
             return new ArrayList<>();
diff --git a/src/test/java/com/zy/common/utils/NavigateUtilsTest.java b/src/test/java/com/zy/common/utils/NavigateUtilsTest.java
new file mode 100644
index 0000000..2318053
--- /dev/null
+++ b/src/test/java/com/zy/common/utils/NavigateUtilsTest.java
@@ -0,0 +1,49 @@
+package com.zy.common.utils;
+
+import com.alibaba.fastjson.JSONObject;
+import com.zy.common.model.NavigateNode;
+import org.junit.jupiter.api.Test;
+import org.springframework.test.util.ReflectionTestUtils;
+
+import java.util.List;
+import java.util.stream.Collectors;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+class NavigateUtilsTest {
+
+    @Test
+    void normalizeStationPath_keepsLoopRevisitStationsWhileCompressingAdjacentDuplicates() {
+        NavigateUtils navigateUtils = new NavigateUtils();
+
+        @SuppressWarnings("unchecked")
+        List<NavigateNode> normalizedPath = (List<NavigateNode>) ReflectionTestUtils.invokeMethod(
+                navigateUtils,
+                "normalizeStationPath",
+                List.of(
+                        buildNode(121, 0, 0),
+                        buildNode(121, 0, 1),
+                        buildNode(124, 0, 2),
+                        buildNode(186, 0, 3),
+                        buildNode(189, 0, 4),
+                        buildNode(121, 0, 5),
+                        buildNode(124, 0, 6),
+                        buildNode(124, 0, 7),
+                        buildNode(125, 0, 8),
+                        buildNode(127, 0, 9)
+                )
+        );
+
+        List<Integer> stationIdList = normalizedPath.stream()
+                .map(node -> JSONObject.parseObject(node.getNodeValue()).getInteger("stationId"))
+                .collect(Collectors.toList());
+
+        assertEquals(List.of(121, 124, 186, 189, 121, 124, 125, 127), stationIdList);
+    }
+
+    private NavigateNode buildNode(int stationId, int x, int y) {
+        NavigateNode node = new NavigateNode(x, y);
+        node.setNodeValue("{\"stationId\":" + stationId + "}");
+        return node;
+    }
+}
diff --git a/src/test/java/com/zy/core/thread/impl/station/StationSegmentExecutorTest.java b/src/test/java/com/zy/core/thread/impl/station/StationSegmentExecutorTest.java
index abb018b..8722170 100644
--- a/src/test/java/com/zy/core/thread/impl/station/StationSegmentExecutorTest.java
+++ b/src/test/java/com/zy/core/thread/impl/station/StationSegmentExecutorTest.java
@@ -14,9 +14,11 @@
 import org.springframework.context.ApplicationContext;
 import org.springframework.test.util.ReflectionTestUtils;
 
+import java.util.List;
 import java.util.function.Function;
 
 import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertEquals;
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.never;
@@ -26,6 +28,37 @@
 class StationSegmentExecutorTest {
 
     @Test
+    void resolveCurrentPathIndex_prefersForwardOccurrenceForLoopRevisitStations() {
+        StationSegmentExecutor executor = new StationSegmentExecutor(new DeviceConfig(), mock(RedisUtil.class), command -> null);
+
+        Integer second121Index = ReflectionTestUtils.invokeMethod(
+                executor,
+                "resolveCurrentPathIndex",
+                List.of(121, 124, 186, 189, 121, 124, 125, 127),
+                121,
+                3
+        );
+        Integer second124Index = ReflectionTestUtils.invokeMethod(
+                executor,
+                "resolveCurrentPathIndex",
+                List.of(121, 124, 186, 189, 121, 124, 125, 127),
+                124,
+                4
+        );
+        Integer same124Index = ReflectionTestUtils.invokeMethod(
+                executor,
+                "resolveCurrentPathIndex",
+                List.of(121, 124, 186, 189, 121, 124, 125, 127),
+                124,
+                5
+        );
+
+        assertEquals(Integer.valueOf(4), second121Index);
+        assertEquals(Integer.valueOf(5), second124Index);
+        assertEquals(Integer.valueOf(5), same124Index);
+    }
+
+    @Test
     void sendSegmentWithRetry_skipsWhenRouteIsCancelPending() {
         ApplicationContext applicationContext = mock(ApplicationContext.class);
         StationMoveCoordinator coordinator = new StationMoveCoordinator();
diff --git a/src/test/java/com/zy/core/thread/impl/station/StationSegmentPlannerTest.java b/src/test/java/com/zy/core/thread/impl/station/StationSegmentPlannerTest.java
new file mode 100644
index 0000000..440a574
--- /dev/null
+++ b/src/test/java/com/zy/core/thread/impl/station/StationSegmentPlannerTest.java
@@ -0,0 +1,49 @@
+package com.zy.core.thread.impl.station;
+
+import com.zy.core.enums.StationCommandType;
+import com.zy.core.model.command.StationCommand;
+import org.junit.jupiter.api.Test;
+
+import java.util.List;
+import java.util.stream.Collectors;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+class StationSegmentPlannerTest {
+
+    @Test
+    void buildPlan_usesLaterLiftTransferOccurrencesWhenLoopPathRevisitsStations() {
+        StationSegmentPlanner planner = new StationSegmentPlanner();
+
+        StationCommand original = new StationCommand();
+        original.setTaskNo(11017);
+        original.setCommandType(StationCommandType.MOVE);
+        original.setStationId(121);
+        original.setTargetStaNo(127);
+        original.setNavigatePath(List.of(121, 124, 186, 189, 121, 124, 125, 127));
+        original.setLiftTransferPath(List.of(121, 124, 186, 189, 121, 124, 127));
+
+        StationSegmentExecutionPlan plan = planner.buildPlan(original);
+
+        assertEquals(
+                List.of(
+                        List.of(121, 124),
+                        List.of(124, 186),
+                        List.of(186, 189),
+                        List.of(189, 121),
+                        List.of(121, 124),
+                        List.of(124, 125, 127)
+                ),
+                plan.getSegmentCommands().stream()
+                        .map(StationCommand::getNavigatePath)
+                        .collect(Collectors.toList())
+        );
+        assertEquals(List.of(1, 2, 3, 4, 5, 6),
+                plan.getSegmentCommands().stream()
+                        .map(StationCommand::getSegmentNo)
+                        .collect(Collectors.toList()));
+        assertTrue(plan.getSegmentCommands().stream()
+                .allMatch(command -> Integer.valueOf(6).equals(command.getSegmentCount())));
+    }
+}

--
Gitblit v1.9.1