张世豪
2025-12-03 2894ac736f8e09f1774b6d4727ac9ced9613e45a
src/dikuai/Dikuaiguanli.java
@@ -15,6 +15,7 @@
import java.util.HashMap;
import java.util.List;
import java.util.ArrayList;
import java.util.Collections;
import zhangaiwu.AddDikuai;
import zhangaiwu.Obstacledge;
@@ -61,6 +62,7 @@
   private ImageIcon boundaryVisibleIcon;
   private ImageIcon boundaryHiddenIcon;
   private static final int BOUNDARY_TOGGLE_ICON_SIZE = 48;
   private Map<String, ObstacleSummary> obstacleSummaryCache = Collections.emptyMap();
   public Dikuaiguanli(String landNumber) {
      latestInstance = this;
@@ -136,13 +138,15 @@
      cardsPanel.removeAll();
      
      Map<String, Dikuai> allDikuai = Dikuai.getAllDikuai();
      if (allDikuai.isEmpty()) {
         obstacleSummaryCache = Collections.emptyMap();
         // 显示空状态
         JPanel emptyPanel = createEmptyStatePanel();
         cardsPanel.add(emptyPanel);
         setCurrentWorkLand(null, null);
      } else {
         obstacleSummaryCache = loadObstacleSummaries();
         if (allDikuai.size() == 1) {
            Dikuai onlyDikuai = allDikuai.values().iterator().next();
            setCurrentWorklandIfNeeded(onlyDikuai);
@@ -241,12 +245,12 @@
      contentPanel.add(boundaryPanel);
   contentPanel.add(Box.createRigidArea(new Dimension(0, 20)));
      
      // 障碍物坐标(带新增和查看按钮)
      JPanel obstaclePanel = createCardInfoItemWithButton("障碍物坐标:",
         getTruncatedValue(dikuai.getObstacleCoordinates(), 12, "未设置"),
      ObstacleSummary obstacleSummary = getObstacleSummaryFromCache(dikuai.getLandNumber());
      JPanel obstaclePanel = createCardInfoItemWithButton("障碍物:",
         obstacleSummary.buildDisplayValue(),
         "新增",
         e -> addNewObstacle(dikuai));
      setInfoItemTooltip(obstaclePanel, dikuai.getObstacleCoordinates());
      setInfoItemTooltip(obstaclePanel, obstacleSummary.buildTooltip());
      contentPanel.add(obstaclePanel);
   contentPanel.add(Box.createRigidArea(new Dimension(0, 20)));
@@ -665,15 +669,22 @@
         }
         MapRenderer renderer = shouye.getMapRenderer();
         if (renderer != null) {
            renderer.applyLandMetadata(dikuai);
            String boundary = (dikuai != null) ? dikuai.getBoundaryCoordinates() : null;
            String plannedPath = (dikuai != null) ? dikuai.getPlannedPath() : null;
            String obstacles = (dikuai != null) ? dikuai.getObstacleCoordinates() : null;
            List<Obstacledge.Obstacle> configuredObstacles = (landNumber != null) ? loadObstaclesFromConfig(landNumber) : null;
            renderer.setCurrentBoundary(boundary, landNumber, landNumber == null ? null : landName);
            renderer.setCurrentPlannedPath(plannedPath);
            renderer.setCurrentObstacles(obstacles, landNumber);
            if (configuredObstacles != null) {
               renderer.setCurrentObstacles(configuredObstacles, landNumber);
            } else {
               renderer.setCurrentObstacles(obstacles, landNumber);
            }
            boolean showBoundaryPoints = landNumber != null && boundaryPointVisibility.getOrDefault(landNumber, false);
            renderer.setBoundaryPointsVisible(showBoundaryPoints);
         }
         shouye.refreshMowingIndicators();
      }
   }
@@ -734,39 +745,103 @@
      loadDikuaiData();
   }
   private Map<String, ObstacleSummary> loadObstacleSummaries() {
      Map<String, ObstacleSummary> summaries = new HashMap<>();
      try {
         File configFile = new File("Obstacledge.properties");
         if (!configFile.exists()) {
            return summaries;
         }
         Obstacledge.ConfigManager manager = new Obstacledge.ConfigManager();
         if (!manager.loadFromFile(configFile.getAbsolutePath())) {
            return summaries;
         }
         for (Obstacledge.Plot plot : manager.getPlots()) {
            if (plot == null) {
               continue;
            }
            String plotId = plot.getPlotId();
            if (plotId == null || plotId.trim().isEmpty()) {
               continue;
            }
            List<String> names = new ArrayList<>();
            for (Obstacledge.Obstacle obstacle : plot.getObstacles()) {
               if (obstacle == null) {
                  continue;
               }
               String name = obstacle.getObstacleName();
               if (name == null) {
                  continue;
               }
               String trimmed = name.trim();
               if (!trimmed.isEmpty()) {
                  names.add(trimmed);
               }
            }
            summaries.put(plotId.trim(), ObstacleSummary.of(names));
         }
      } catch (Exception ex) {
         System.err.println("读取障碍物配置失败: " + ex.getMessage());
      }
      return summaries;
   }
   private static List<Obstacledge.Obstacle> loadObstaclesFromConfig(String landNumber) {
      if (landNumber == null || landNumber.trim().isEmpty()) {
         return Collections.emptyList();
      }
      try {
         File configFile = new File("Obstacledge.properties");
         if (!configFile.exists()) {
            return null;
         }
         Obstacledge.ConfigManager manager = new Obstacledge.ConfigManager();
         if (!manager.loadFromFile(configFile.getAbsolutePath())) {
            return null;
         }
         Obstacledge.Plot plot = manager.getPlotById(landNumber.trim());
         if (plot == null) {
            return Collections.emptyList();
         }
         List<Obstacledge.Obstacle> obstacles = plot.getObstacles();
         if (obstacles == null || obstacles.isEmpty()) {
            return Collections.emptyList();
         }
         return new ArrayList<>(obstacles);
      } catch (Exception ex) {
         System.err.println("读取障碍物配置失败: " + ex.getMessage());
         return null;
      }
   }
   private ObstacleSummary getObstacleSummaryFromCache(String landNumber) {
      if (landNumber == null || landNumber.trim().isEmpty()) {
         return ObstacleSummary.empty();
      }
      if (obstacleSummaryCache == null || obstacleSummaryCache.isEmpty()) {
         return ObstacleSummary.empty();
      }
      ObstacleSummary summary = obstacleSummaryCache.get(landNumber.trim());
      return summary != null ? summary : ObstacleSummary.empty();
   }
   private List<String> loadObstacleNamesForLand(String landNumber) {
      List<String> names = new ArrayList<>();
      if (landNumber == null || landNumber.trim().isEmpty()) {
         return names;
      }
      try {
         File configFile = new File("Obstacledge.properties");
         if (!configFile.exists()) {
            return names;
         }
         Obstacledge.ConfigManager manager = new Obstacledge.ConfigManager();
         if (!manager.loadFromFile(configFile.getAbsolutePath())) {
            return names;
         }
         Obstacledge.Plot plot = manager.getPlotById(landNumber.trim());
         if (plot == null) {
            return names;
         }
         for (Obstacledge.Obstacle obstacle : plot.getObstacles()) {
            if (obstacle == null) {
               continue;
            }
            String name = obstacle.getObstacleName();
            if (name == null) {
               continue;
            }
            String trimmed = name.trim();
            if (!trimmed.isEmpty() && !names.contains(trimmed)) {
               names.add(trimmed);
            }
         }
      } catch (Exception ex) {
         System.err.println("读取障碍物配置失败: " + ex.getMessage());
      ObstacleSummary cached = getObstacleSummaryFromCache(landNumber);
      if (!cached.isEmpty()) {
         names.addAll(cached.copyNames());
         return names;
      }
      Map<String, ObstacleSummary> latest = loadObstacleSummaries();
      if (!latest.isEmpty()) {
         obstacleSummaryCache = latest;
      }
      ObstacleSummary refreshed = getObstacleSummaryFromCache(landNumber);
      if (!refreshed.isEmpty()) {
         names.addAll(refreshed.copyNames());
      }
      return names;
   }
@@ -887,4 +962,68 @@
      }
      boundaryPointVisibility.put(landNumber, visible);
   }
   private static final class ObstacleSummary {
      private static final ObstacleSummary EMPTY = new ObstacleSummary(Collections.emptyList());
      private final List<String> names;
      private ObstacleSummary(List<String> names) {
         this.names = names;
      }
      static ObstacleSummary of(List<String> originalNames) {
         if (originalNames == null || originalNames.isEmpty()) {
            return empty();
         }
         List<String> cleaned = new ArrayList<>();
         for (String name : originalNames) {
            if (name == null) {
               continue;
            }
            String trimmed = name.trim();
            if (trimmed.isEmpty()) {
               continue;
            }
            boolean duplicated = false;
            for (String existing : cleaned) {
               if (existing.equalsIgnoreCase(trimmed)) {
                  duplicated = true;
                  break;
               }
            }
            if (!duplicated) {
               cleaned.add(trimmed);
            }
         }
         if (cleaned.isEmpty()) {
            return empty();
         }
         cleaned.sort(String::compareToIgnoreCase);
         return new ObstacleSummary(Collections.unmodifiableList(cleaned));
      }
      static ObstacleSummary empty() {
         return EMPTY;
      }
      boolean isEmpty() {
         return names.isEmpty();
      }
      int count() {
         return names.size();
      }
      String buildDisplayValue() {
         return count() > 0 ? String.format("障碍物%d个", count()) : "暂无障碍物";
      }
      String buildTooltip() {
         return count() > 0 ? String.join(",", names) : "暂无障碍物";
      }
      List<String> copyNames() {
         return new ArrayList<>(names);
      }
   }
}