From 5ae9bbe3583384afab8eb95a134ccb74aee6487a Mon Sep 17 00:00:00 2001
From: 张世豪 <979909237@qq.com>
Date: 星期四, 25 十二月 2025 13:46:38 +0800
Subject: [PATCH] 曾加修改密码功能

---
 src/lujing/AoxinglujingNoObstacle.java |   78 ++++++
 src/set/Sets.java                      |   57 ++++
 set.properties                         |    4 
 src/set/xiugaimima.java                |  276 +++++++++++++++++++++
 src/Mqttmessage/Client.java            |  308 ++++++++++++++++++++++-
 5 files changed, 700 insertions(+), 23 deletions(-)

diff --git a/set.properties b/set.properties
index ed82d7f..4d5600c 100644
--- a/set.properties
+++ b/set.properties
@@ -1,5 +1,5 @@
 #Mower Configuration Properties - Updated
-#Thu Dec 25 12:21:15 CST 2025
+#Thu Dec 25 13:40:36 CST 2025
 appVersion=-1
 boundaryLengthVisible=false
 currentWorkLandNumber=LAND1
@@ -8,7 +8,7 @@
 handheldMarkerId=1872
 idleTrailDurationSeconds=60
 manualBoundaryDrawingMode=false
-mapScale=0.78
+mapScale=0.93
 measurementModeEnabled=false
 mowerId=6258
 serialAutoConnect=true
diff --git a/src/Mqttmessage/Client.java b/src/Mqttmessage/Client.java
index 60be1c3..de7d4a8 100644
--- a/src/Mqttmessage/Client.java
+++ b/src/Mqttmessage/Client.java
@@ -3,6 +3,7 @@
 import org.eclipse.paho.client.mqttv3.MqttClient;
 import org.eclipse.paho.client.mqttv3.MqttConnectOptions;
 import org.eclipse.paho.client.mqttv3.MqttException;
+import org.eclipse.paho.client.mqttv3.persist.MemoryPersistence;
 
 import set.Setsys;
 import user.Usrdell;
@@ -19,6 +20,10 @@
     private MqttClient client;
     private MqttConnectOptions options;
     
+    // 闈欐�佸彉閲忕敤浜庡瓨鍌ㄥ鎴风瀹炰緥
+    private static Client gpsClient;
+    private static Client responseClient;
+    
     /**
      * 鏋勯�犲嚱鏁�
      * @param host MQTT鏈嶅姟鍣ㄥ湴鍧�锛屾牸寮忥細tcp://ip:port
@@ -26,12 +31,19 @@
      * @param clientId 瀹㈡埛绔疘D锛屼笉鑳介噸澶�
      */
     public Client(String host, String topic, String clientId) {
-
         this.host = host;
         this.topic = topic;
         this.clientId = clientId;
         this.options = new MqttConnectOptions();
         this.options.setCleanSession(true);
+        // 璁剧疆杩炴帴瓒呮椂鏃堕棿锛堢锛�
+        this.options.setConnectionTimeout(30);
+        // 璁剧疆KeepAlive闂撮殧锛堢锛夛紝鐢ㄤ簬淇濇寔杩炴帴娲昏穬
+        this.options.setKeepAliveInterval(60);
+        // 璁剧疆鑷姩閲嶈繛
+        this.options.setAutomaticReconnect(true);
+        // 璁剧疆MQTT鐗堟湰锛屼娇鐢�3.1.1
+        this.options.setMqttVersion(MqttConnectOptions.MQTT_VERSION_3_1_1);
     }
     
     /**
@@ -40,11 +52,28 @@
      */
     public void connect() throws MqttException {
         if (client != null && client.isConnected()) {
+            System.out.println("MQTT瀹㈡埛绔凡杩炴帴锛孋lientId: " + clientId);
             return;
         }
-        client = new MqttClient(host, clientId);
-        client.connect(options);
+        
+        // 濡傛灉瀹㈡埛绔凡瀛樺湪浣嗘湭杩炴帴锛屽厛鍏抽棴
+        if (client != null) {
+            try {
+                client.close();
+            } catch (Exception e) {
+                // 蹇界暐鍏抽棴鏃剁殑寮傚父
+            }
+            client = null;
+        }
+        
+        // 浣跨敤鍐呭瓨鎸佷箙鍖栵紝閬垮厤鏂囦欢閿佸畾闂
+        client = new MqttClient(host, clientId, new MemoryPersistence());
+        // 鍏堣缃洖璋冿紝鍐嶈繛鎺�
         client.setCallback(new PushCallback());
+        
+        // 鎵ц杩炴帴
+        client.connect(options);
+        System.out.println("MQTT杩炴帴鎴愬姛锛丆lientId: " + clientId + ", 鏈嶅姟鍣�: " + host + ", 涓婚: " + topic);
     }
     
     /**
@@ -78,6 +107,23 @@
     }
     
     /**
+     * 鍏抽棴瀹㈡埛绔苟閲婃斁璧勬簮
+     */
+    public void close() {
+        try {
+            if (client != null) {
+                if (client.isConnected()) {
+                    client.disconnect();
+                }
+                client.close();
+                client = null;
+            }
+        } catch (Exception e) {
+            // 蹇界暐鍏抽棴鏃剁殑寮傚父
+        }
+    }
+    
+    /**
      * 妫�鏌ユ槸鍚﹀凡杩炴帴
      * @return true琛ㄧず宸茶繛鎺ワ紝false琛ㄧず鏈繛鎺�
      */
@@ -94,29 +140,249 @@
     }
     
     /**
-     * 绀轰緥鐢ㄦ硶
+     * 杩炴帴MQTT鏈嶅姟鍣ㄧ殑宸ュ叿鏂规硶
+     * 渚涘叾浠栫被鐩存帴璋冪敤锛岃繛鎺PS涓婚鍜屽搷搴斾富棰�
+     * @return true琛ㄧず杩炴帴鎴愬姛锛宖alse琛ㄧず杩炴帴澶辫触
      */
-
-    public static void lianjiemqqt()  {
+    public static boolean connectMQTT() {
+        // 鍏堟柇寮�涔嬪墠鐨勮繛鎺�
+        disconnectAll();
+        
+        boolean gpsSuccess = false;
+        boolean responseSuccess = false;
+        
         try {
             String host = "tcp://39.99.43.227:1883";
-            String deiveID=Setsys.getMowerIdValue();
-            String clientId =Usrdell.getUserEmail()+"mower";
-            String clientId2 =Usrdell.getUserEmail()+"response";
-            String topic = "mower/"+deiveID+"/gps";
-            String topic2 = "mower/"+deiveID+"/response";
-            Client mqttClient = new Client(host, topic, clientId);
-            Client mqttClient1 = new Client(host, topic2, clientId2);
-            mqttClient.connect();
-            mqttClient.subscribe();
+            String deiveID = Setsys.getMowerIdValue();
+            // 娣诲姞鏃堕棿鎴崇‘淇濆鎴风ID鍞竴
+            long timestamp = System.currentTimeMillis();
+            String clientId = Usrdell.getUserEmail() + "mower" + "_" + timestamp;
+            String clientId2 = Usrdell.getUserEmail() + "response" + "_" + timestamp;
+            String topic = "mower/" + deiveID + "/gps";
+            String topic2 = "mower/" + deiveID + "/response";
+            
+            // 杩炴帴GPS涓婚
+            try {
+                gpsClient = new Client(host, topic, clientId);
+                gpsClient.connect();
+                // 绋嶄綔寤惰繜锛岀‘淇濊繛鎺ョǔ瀹�
+                Thread.sleep(100);
+                gpsClient.subscribe();
+                gpsSuccess = true;
+                System.out.println("GPS涓婚MQTT杩炴帴骞惰闃呮垚鍔�");
+            } catch (MqttException e) {
+                System.err.println("GPS涓婚MQTT杩炴帴澶辫触: " + e.getMessage());
+                if (e.getCause() != null) {
+                    System.err.println("澶辫触鍘熷洜: " + e.getCause().getMessage());
+                }
+                e.printStackTrace();
+            } catch (InterruptedException e) {
+                Thread.currentThread().interrupt();
+                System.err.println("杩炴帴杩囩▼琚腑鏂�");
+            }
 
-            mqttClient1.connect();
-            mqttClient1.subscribe();
+            // 杩炴帴鍝嶅簲涓婚
+            try {
+                responseClient = new Client(host, topic2, clientId2);
+                responseClient.connect();
+                // 绋嶄綔寤惰繜锛岀‘淇濊繛鎺ョǔ瀹�
+                Thread.sleep(100);
+                responseClient.subscribe();
+                responseSuccess = true;
+                System.out.println("鍝嶅簲涓婚MQTT杩炴帴骞惰闃呮垚鍔�");
+            } catch (MqttException e) {
+                System.err.println("鍝嶅簲涓婚MQTT杩炴帴澶辫触: " + e.getMessage());
+                if (e.getCause() != null) {
+                    System.err.println("澶辫触鍘熷洜: " + e.getCause().getMessage());
+                }
+                e.printStackTrace();
+            } catch (InterruptedException e) {
+                Thread.currentThread().interrupt();
+                System.err.println("杩炴帴杩囩▼琚腑鏂�");
+            }
 
-            // 淇濇寔绋嬪簭杩愯
-//           Thread.sleep(Long.MAX_VALUE);
-        } catch (MqttException e) {
-            throw new RuntimeException(e);
+            if (gpsSuccess && responseSuccess) {
+                System.out.println("鎵�鏈塎QTT涓婚杩炴帴骞惰闃呮垚鍔燂紒");
+                return true;
+            } else if (gpsSuccess || responseSuccess) {
+                System.out.println("閮ㄥ垎MQTT涓婚杩炴帴鎴愬姛");
+                return true;
+            } else {
+                System.err.println("鎵�鏈塎QTT涓婚杩炴帴澶辫触");
+                return false;
+            }
+        } catch (Exception e) {
+            System.err.println("MQTT杩炴帴杩囩▼鍙戠敓寮傚父: " + e.getMessage());
+            e.printStackTrace();
+            return false;
         }
     }
+    
+    /**
+     * 杩炴帴MQTT鏈嶅姟鍣ㄧ殑宸ュ叿鏂规硶锛堝甫鍙傛暟鐗堟湰锛�
+     * @param host MQTT鏈嶅姟鍣ㄥ湴鍧�锛屾牸寮忥細tcp://ip:port
+     * @param deviceId 璁惧ID
+     * @param userEmail 鐢ㄦ埛閭
+     * @return true琛ㄧず杩炴帴鎴愬姛锛宖alse琛ㄧず杩炴帴澶辫触
+     */
+    public static boolean connectMQTT(String host, String deviceId, String userEmail) {
+        // 鍏堟柇寮�涔嬪墠鐨勮繛鎺�
+        disconnectAll();
+        
+        boolean gpsSuccess = false;
+        boolean responseSuccess = false;
+        
+        try {
+            // 娣诲姞鏃堕棿鎴崇‘淇濆鎴风ID鍞竴
+            long timestamp = System.currentTimeMillis();
+            String clientId = userEmail + "mower" + "_" + timestamp;
+            String clientId2 = userEmail + "response" + "_" + timestamp;
+            String topic = "mower/" + deviceId + "/gps";
+            String topic2 = "mower/" + deviceId + "/response";
+            
+            // 杩炴帴GPS涓婚
+            try {
+                gpsClient = new Client(host, topic, clientId);
+                gpsClient.connect();
+                // 绋嶄綔寤惰繜锛岀‘淇濊繛鎺ョǔ瀹�
+                Thread.sleep(100);
+                gpsClient.subscribe();
+                gpsSuccess = true;
+                System.out.println("GPS涓婚MQTT杩炴帴骞惰闃呮垚鍔�");
+            } catch (MqttException e) {
+                System.err.println("GPS涓婚MQTT杩炴帴澶辫触: " + e.getMessage());
+                if (e.getCause() != null) {
+                    System.err.println("澶辫触鍘熷洜: " + e.getCause().getMessage());
+                }
+                e.printStackTrace();
+            } catch (InterruptedException e) {
+                Thread.currentThread().interrupt();
+                System.err.println("杩炴帴杩囩▼琚腑鏂�");
+            }
+
+            // 杩炴帴鍝嶅簲涓婚
+            try {
+                responseClient = new Client(host, topic2, clientId2);
+                responseClient.connect();
+                // 绋嶄綔寤惰繜锛岀‘淇濊繛鎺ョǔ瀹�
+                Thread.sleep(100);
+                responseClient.subscribe();
+                responseSuccess = true;
+                System.out.println("鍝嶅簲涓婚MQTT杩炴帴骞惰闃呮垚鍔�");
+            } catch (MqttException e) {
+                System.err.println("鍝嶅簲涓婚MQTT杩炴帴澶辫触: " + e.getMessage());
+                if (e.getCause() != null) {
+                    System.err.println("澶辫触鍘熷洜: " + e.getCause().getMessage());
+                }
+                e.printStackTrace();
+            } catch (InterruptedException e) {
+                Thread.currentThread().interrupt();
+                System.err.println("杩炴帴杩囩▼琚腑鏂�");
+            }
+
+            if (gpsSuccess && responseSuccess) {
+                System.out.println("鎵�鏈塎QTT涓婚杩炴帴骞惰闃呮垚鍔燂紒");
+                return true;
+            } else if (gpsSuccess || responseSuccess) {
+                System.out.println("閮ㄥ垎MQTT涓婚杩炴帴鎴愬姛");
+                return true;
+            } else {
+                System.err.println("鎵�鏈塎QTT涓婚杩炴帴澶辫触");
+                return false;
+            }
+        } catch (Exception e) {
+            System.err.println("MQTT杩炴帴杩囩▼鍙戠敓寮傚父: " + e.getMessage());
+            e.printStackTrace();
+            return false;
+        }
+    }
+    
+    /**
+     * 鍒涘缓骞惰繛鎺QTT瀹㈡埛绔殑宸ュ叿鏂规硶
+     * @param host MQTT鏈嶅姟鍣ㄥ湴鍧�
+     * @param topic 璁㈤槄涓婚
+     * @param clientId 瀹㈡埛绔疘D
+     * @param qos 鏈嶅姟璐ㄩ噺绛夌骇锛岄粯璁�2
+     * @return Client瀹炰緥锛岃繛鎺ュけ璐ヨ繑鍥瀗ull
+     */
+    public static Client createAndConnect(String host, String topic, String clientId, int qos) {
+        try {
+            Client mqttClient = new Client(host, topic, clientId);
+            mqttClient.connect();
+            mqttClient.subscribe(qos);
+            System.out.println("MQTT瀹㈡埛绔垱寤哄苟璁㈤槄鎴愬姛锛屼富棰�: " + topic + ", ClientId: " + clientId);
+            return mqttClient;
+        } catch (MqttException e) {
+            System.err.println("MQTT瀹㈡埛绔垱寤哄け璐�: " + e.getMessage() + ", 涓婚: " + topic);
+            e.printStackTrace();
+            return null;
+        }
+    }
+    
+    /**
+     * 鍒涘缓骞惰繛鎺QTT瀹㈡埛绔殑宸ュ叿鏂规硶锛堥粯璁oS涓�2锛�
+     * @param host MQTT鏈嶅姟鍣ㄥ湴鍧�
+     * @param topic 璁㈤槄涓婚
+     * @param clientId 瀹㈡埛绔疘D
+     * @return Client瀹炰緥锛岃繛鎺ュけ璐ヨ繑鍥瀗ull
+     */
+    public static Client createAndConnect(String host, String topic, String clientId) {
+        return createAndConnect(host, topic, clientId, 2);
+    }
+    
+    /**
+     * 鏂紑鎵�鏈塎QTT杩炴帴
+     */
+    public static void disconnectAll() {
+        try {
+            if (gpsClient != null) {
+                gpsClient.close();
+                System.out.println("GPS涓婚MQTT杩炴帴宸叉柇寮�");
+                gpsClient = null;
+            }
+            if (responseClient != null) {
+                responseClient.close();
+                System.out.println("鍝嶅簲涓婚MQTT杩炴帴宸叉柇寮�");
+                responseClient = null;
+            }
+        } catch (Exception e) {
+            System.err.println("鏂紑MQTT杩炴帴澶辫触: " + e.getMessage());
+            e.printStackTrace();
+        }
+    }
+    
+    /**
+     * 鑾峰彇GPS瀹㈡埛绔疄渚�
+     * @return GPS瀹㈡埛绔疄渚�
+     */
+    public static Client getGpsClient() {
+        return gpsClient;
+    }
+    
+    /**
+     * 鑾峰彇鍝嶅簲瀹㈡埛绔疄渚�
+     * @return 鍝嶅簲瀹㈡埛绔疄渚�
+     */
+    public static Client getResponseClient() {
+        return responseClient;
+    }
+    
+    /**
+     * 妫�鏌QTT杩炴帴鐘舵�侊紙闈欐�佹柟娉曪級
+     * @return true琛ㄧず宸茶繛鎺ワ紝false琛ㄧず鏈繛鎺�
+     */
+    public static boolean areClientsConnected() {
+        boolean gpsConnected = gpsClient != null && gpsClient.isConnected();
+        boolean responseConnected = responseClient != null && responseClient.isConnected();
+        return gpsConnected || responseConnected;
+    }
+    
+    /**
+     * 绀轰緥鐢ㄦ硶锛堜繚鐣欏悜鍚庡吋瀹癸級
+     * @deprecated 璇蜂娇鐢� connectMQTT() 鏂规硶鏇夸唬
+     */
+    @Deprecated
+    public static void lianjiemqqt() {
+        connectMQTT();
+    }
 }
\ No newline at end of file
diff --git a/src/lujing/AoxinglujingNoObstacle.java b/src/lujing/AoxinglujingNoObstacle.java
index fe884f9..4bdf628 100644
--- a/src/lujing/AoxinglujingNoObstacle.java
+++ b/src/lujing/AoxinglujingNoObstacle.java
@@ -38,6 +38,14 @@
         return planPathCore(originalPolygon, width, margin);
     }
 
+    /**
+     * 鏍稿績璺緞瑙勫垝閫昏緫
+     * 
+     * @param originalPolygon 鍘熷澶氳竟褰㈤《鐐瑰垪琛�
+     * @param width 鍓茶崏瀹藉害
+     * @param margin 瀹夊叏杈硅窛
+     * @return 瑙勫垝濂界殑璺緞娈靛垪琛�
+     */
     private static List<PathSegment> planPathCore(List<Point> originalPolygon, double width, double margin) {
         if (originalPolygon.size() < 3) return new ArrayList<>();
 
@@ -74,6 +82,11 @@
 
     /**
      * 瀵绘壘寮撳瓧褰㈢殑绗竴鏉$嚎鐨勮捣鐐�
+     * 
+     * @param polygon 澶氳竟褰㈤《鐐瑰垪琛�
+     * @param angle 鎵弿瑙掑害
+     * @param width 鍓茶崏瀹藉害
+     * @return 鎵弿璧风偣鐨勫潗鏍�
      */
     private static Point getFirstScanStartPoint(List<Point> polygon, double angle, double width) {
         List<Point> rotated = rotatePolygon(polygon, -angle);
@@ -90,6 +103,10 @@
 
     /**
      * 閲嶇粍澶氳竟褰㈤《鐐癸紝浣垮緱绱㈠紩0鐨勭偣鏈�闈犺繎濉厖璧风偣
+     * 
+     * @param polygon 澶氳竟褰㈤《鐐瑰垪琛�
+     * @param target 鐩爣鐐癸紙濉厖璧风偣锛�
+     * @return 閲嶇粍鍚庣殑澶氳竟褰㈤《鐐瑰垪琛�
      */
     private static List<Point> alignBoundaryToStart(List<Point> polygon, Point target) {
         int bestIdx = 0;
@@ -108,6 +125,15 @@
         return aligned;
     }
 
+    /**
+     * 鐢熸垚寮撳瓧褰㈡壂鎻忚矾寰�
+     * 
+     * @param polygon 澶氳竟褰㈤《鐐瑰垪琛�
+     * @param angle 鎵弿瑙掑害
+     * @param width 鍓茶崏瀹藉害
+     * @param startPoint 璧峰鐐�
+     * @return 寮撳瓧褰㈣矾寰勬鍒楄〃
+     */
     private static List<PathSegment> generateZigZagPath(List<Point> polygon, double angle, double width, Point startPoint) {
         List<PathSegment> result = new ArrayList<>();
         List<Point> rotated = rotatePolygon(polygon, -angle);
@@ -143,6 +169,13 @@
         return result;
     }
 
+    /**
+     * 鑾峰彇鎵弿绾夸笌澶氳竟褰㈢殑浜ょ偣X鍧愭爣鍒楄〃
+     * 
+     * @param rotatedPoly 鏃嬭浆鍚庣殑澶氳竟褰�
+     * @param y 鎵弿绾跨殑Y鍧愭爣
+     * @return 浜ょ偣X鍧愭爣鍒楄〃
+     */
     private static List<Double> getXIntersections(List<Point> rotatedPoly, double y) {
         List<Double> xIntersections = new ArrayList<>();
         int n = rotatedPoly.size();
@@ -159,6 +192,13 @@
 
     // --- 鍑犱綍鍩虹宸ュ叿 ---
 
+    /**
+     * 澶氳竟褰㈠唴缂╋紙璁$畻瀹夊叏宸ヤ綔鍖哄煙锛�
+     * 
+     * @param polygon 鍘熷澶氳竟褰�
+     * @param margin 鍐呯缉璺濈
+     * @return 鍐呯缉鍚庣殑澶氳竟褰�
+     */
     private static List<Point> shrinkPolygon(List<Point> polygon, double margin) {
         List<Point> result = new ArrayList<>();
         int n = polygon.size();
@@ -187,6 +227,12 @@
         return result;
     }
 
+    /**
+     * 瀵绘壘鏈�浼樻壂鎻忚搴︼紙浣挎壂鎻忕嚎鏁伴噺鏈�灏戯級
+     * 
+     * @param polygon 澶氳竟褰�
+     * @return 鏈�浼樿搴︼紙寮у害锛�
+     */
     private static double findOptimalScanAngle(List<Point> polygon) {
         double minH = Double.MAX_VALUE;
         double bestA = 0;
@@ -199,6 +245,13 @@
         return bestA;
     }
 
+    /**
+     * 璁$畻澶氳竟褰㈠湪鐗瑰畾瑙掑害涓嬬殑楂樺害锛堟姇褰遍暱搴︼級
+     * 
+     * @param poly 澶氳竟褰�
+     * @param angle 瑙掑害
+     * @return 楂樺害
+     */
     private static double calculatePolygonHeightAtAngle(List<Point> poly, double angle) {
         double minY = Double.MAX_VALUE, maxY = -Double.MAX_VALUE;
         double sin = Math.sin(-angle), cos = Math.cos(-angle);
@@ -209,17 +262,36 @@
         return maxY - minY;
     }
 
+    /**
+     * 鏃嬭浆鐐�
+     * 
+     * @param p 鐐�
+     * @param angle 鏃嬭浆瑙掑害
+     * @return 鏃嬭浆鍚庣殑鐐�
+     */
     private static Point rotatePoint(Point p, double angle) {
         double c = Math.cos(angle), s = Math.sin(angle);
         return new Point(p.x * c - p.y * s, p.x * s + p.y * c);
     }
 
+    /**
+     * 鏃嬭浆澶氳竟褰�
+     * 
+     * @param poly 澶氳竟褰�
+     * @param angle 鏃嬭浆瑙掑害
+     * @return 鏃嬭浆鍚庣殑澶氳竟褰�
+     */
     private static List<Point> rotatePolygon(List<Point> poly, double angle) {
         List<Point> res = new ArrayList<>();
         for (Point p : poly) res.add(rotatePoint(p, angle));
         return res;
     }
 
+    /**
+     * 纭繚澶氳竟褰㈤《鐐逛负閫嗘椂閽堥『搴�
+     * 
+     * @param poly 澶氳竟褰�
+     */
     private static void ensureCCW(List<Point> poly) {
         double s = 0;
         for (int i = 0; i < poly.size(); i++) {
@@ -229,6 +301,12 @@
         if (s > 0) Collections.reverse(poly);
     }
 
+    /**
+     * 瑙f瀽鍧愭爣瀛楃涓�
+     * 
+     * @param s 鍧愭爣瀛楃涓� (鏍煎紡: "x1,y1;x2,y2;...")
+     * @return 鐐瑰垪琛�
+     */
     private static List<Point> parseCoords(String s) {
         List<Point> list = new ArrayList<>();
         for (String p : s.split(";")) {
diff --git a/src/set/Sets.java b/src/set/Sets.java
index 2379b27..bbc0160 100644
--- a/src/set/Sets.java
+++ b/src/set/Sets.java
@@ -193,6 +193,9 @@
         JPanel manualBoundaryDrawingPanel = createManualBoundaryDrawingPanel();
         manualBoundaryDrawingModeLabel = (JLabel) manualBoundaryDrawingPanel.getClientProperty("valueLabel");
 
+        // 淇敼瀵嗙爜璁剧疆椤�
+        JPanel changePasswordPanel = createChangePasswordPanel();
+
         JPanel feedbackPanel = createFeedbackPanel();
         
         // APP鐗堟湰
@@ -214,6 +217,7 @@
         addSettingItem(panel, boundaryLengthPanel, true);
         addSettingItem(panel, measurementModePanel, true);
         addSettingItem(panel, manualBoundaryDrawingPanel, true);
+        addSettingItem(panel, changePasswordPanel, true);
         addSettingItem(panel, feedbackPanel, true);
         addSettingItem(panel, appVersionPanel, true);
         addSettingItem(panel, logoutPanel, false);  // 鏈�鍚庝竴椤逛笉鍔犲垎鍓茬嚎
@@ -1860,4 +1864,57 @@
         
         return panel;
     }
+
+    /**
+     * 鍒涘缓淇敼瀵嗙爜璁剧疆闈㈡澘
+     */
+    private JPanel createChangePasswordPanel() {
+        JPanel panel = new JPanel(new GridBagLayout());
+        panel.setOpaque(false);
+        panel.setAlignmentX(Component.LEFT_ALIGNMENT);
+        panel.setMaximumSize(new Dimension(Integer.MAX_VALUE, ROW_HEIGHT));
+        panel.setPreferredSize(new Dimension(Integer.MAX_VALUE, ROW_HEIGHT));
+        panel.setMinimumSize(new Dimension(0, ROW_HEIGHT));
+        panel.setBorder(BorderFactory.createEmptyBorder(ITEM_PADDING, ITEM_PADDING, ITEM_PADDING, ITEM_PADDING));
+
+        GridBagConstraints gbc = new GridBagConstraints();
+
+        JLabel titleLabel = new JLabel("淇敼瀵嗙爜");
+        titleLabel.setFont(new Font("寰蒋闆呴粦", Font.BOLD, 14));
+        titleLabel.setForeground(Color.BLACK);
+        titleLabel.setHorizontalAlignment(SwingConstants.RIGHT);
+        gbc.gridx = 0;
+        gbc.gridy = 0;
+        gbc.weightx = 0;
+        gbc.anchor = GridBagConstraints.EAST;
+        gbc.insets = new Insets(0, 0, 0, 12);
+        panel.add(titleLabel, gbc);
+
+        JLabel valueLabel = new JLabel("******");
+        valueLabel.setFont(new Font("寰蒋闆呴粦", Font.PLAIN, 14));
+        valueLabel.setForeground(Color.DARK_GRAY);
+        gbc = new GridBagConstraints();
+        gbc.gridx = 1;
+        gbc.gridy = 0;
+        gbc.weightx = 1.0;
+        gbc.anchor = GridBagConstraints.EAST;
+        panel.add(valueLabel, gbc);
+
+        JButton editBtn = createEditButton();
+        editBtn.addActionListener(e -> {
+            SwingUtilities.invokeLater(() -> {
+                xiugaimima dialog = new xiugaimima((Frame) SwingUtilities.getWindowAncestor(this));
+                dialog.setVisible(true);
+            });
+        });
+        
+        gbc = new GridBagConstraints();
+        gbc.gridx = 2;
+        gbc.gridy = 0;
+        gbc.weightx = 0;
+        gbc.anchor = GridBagConstraints.EAST;
+        panel.add(editBtn, gbc);
+
+        return panel;
+    }
 }
\ No newline at end of file
diff --git a/src/set/xiugaimima.java b/src/set/xiugaimima.java
new file mode 100644
index 0000000..c7ff19a
--- /dev/null
+++ b/src/set/xiugaimima.java
@@ -0,0 +1,276 @@
+package set;
+
+import javax.swing.*;
+import java.awt.*;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.event.MouseAdapter;
+import java.awt.event.MouseEvent;
+import javax.swing.event.DocumentEvent;
+import javax.swing.event.DocumentListener;
+import user.Usrdell;
+
+public class xiugaimima extends JDialog {
+    private static final long serialVersionUID = 1L;
+    private JPasswordField oldPasswordField;
+    private JPasswordField newPasswordField;
+    private JPasswordField confirmPasswordField;
+    private JButton saveButton;
+    private JButton cancelButton;
+    private JLabel errorLabel;
+    private final Color THEME_COLOR = new Color(46, 139, 87);
+
+    public xiugaimima(Frame owner) {
+        super(owner, "淇敼瀵嗙爜", true);
+        initializeUI();
+    }
+
+    private void initializeUI() {
+        setLayout(new BorderLayout());
+        setSize(400, 350);
+        setLocationRelativeTo(getOwner());
+        setResizable(false);
+
+        JPanel mainPanel = new JPanel(new GridBagLayout());
+        mainPanel.setBorder(BorderFactory.createEmptyBorder(20, 20, 20, 20));
+        mainPanel.setBackground(Color.WHITE);
+
+        GridBagConstraints gbc = new GridBagConstraints();
+        gbc.insets = new Insets(10, 10, 10, 10);
+        gbc.fill = GridBagConstraints.HORIZONTAL;
+
+        // 鍘熷瘑鐮�
+        gbc.gridx = 0;
+        gbc.gridy = 0;
+        gbc.weightx = 0;
+        mainPanel.add(new JLabel("鍘熷瘑鐮�:"), gbc);
+
+        oldPasswordField = createStyledPasswordField();
+        gbc.gridx = 1;
+        gbc.gridy = 0;
+        gbc.weightx = 1.0;
+        mainPanel.add(oldPasswordField, gbc);
+
+        // 鏂板瘑鐮�
+        gbc.gridx = 0;
+        gbc.gridy = 1;
+        gbc.weightx = 0;
+        mainPanel.add(new JLabel("鏂板瘑鐮�:"), gbc);
+
+        JPanel newPasswordPanel = createPasswordPanelWithEye(newPasswordField = createStyledPasswordField());
+        gbc.gridx = 1;
+        gbc.gridy = 1;
+        gbc.weightx = 1.0;
+        mainPanel.add(newPasswordPanel, gbc);
+
+        // 纭瀵嗙爜
+        gbc.gridx = 0;
+        gbc.gridy = 2;
+        gbc.weightx = 0;
+        mainPanel.add(new JLabel("纭瀵嗙爜:"), gbc);
+
+        JPanel confirmPasswordPanel = createPasswordPanelWithEye(confirmPasswordField = createStyledPasswordField());
+        gbc.gridx = 1;
+        gbc.gridy = 2;
+        gbc.weightx = 1.0;
+        mainPanel.add(confirmPasswordPanel, gbc);
+
+        // 閿欒鎻愮ず淇℃伅
+        errorLabel = new JLabel("瀵嗙爜闀垮害涓嶈兘灏忎簬6涓瓧绗�");
+        errorLabel.setForeground(Color.GRAY);
+        errorLabel.setFont(new Font("PingFang SC", Font.PLAIN, 12));
+        gbc.gridx = 1;
+        gbc.gridy = 3;
+        gbc.gridwidth = 2;
+        gbc.insets = new Insets(0, 10, 10, 10);
+        mainPanel.add(errorLabel, gbc);
+
+        // 娣诲姞瀵嗙爜杈撳叆鐩戝惉
+        DocumentListener passwordListener = new DocumentListener() {
+            @Override
+            public void insertUpdate(DocumentEvent e) { checkPasswords(); }
+            @Override
+            public void removeUpdate(DocumentEvent e) { checkPasswords(); }
+            @Override
+            public void changedUpdate(DocumentEvent e) { checkPasswords(); }
+        };
+        newPasswordField.getDocument().addDocumentListener(passwordListener);
+        confirmPasswordField.getDocument().addDocumentListener(passwordListener);
+
+        add(mainPanel, BorderLayout.CENTER);
+
+        // 鎸夐挳闈㈡澘
+        JPanel buttonPanel = new JPanel(new FlowLayout(FlowLayout.CENTER, 20, 10));
+        buttonPanel.setBackground(Color.WHITE);
+
+        saveButton = new JButton("淇濆瓨");
+        saveButton.setBackground(THEME_COLOR);
+        saveButton.setForeground(Color.WHITE);
+        saveButton.setFocusPainted(false);
+        saveButton.setPreferredSize(new Dimension(100, 35));
+        saveButton.addActionListener(new ActionListener() {
+            @Override
+            public void actionPerformed(ActionEvent e) {
+                handleSave();
+            }
+        });
+
+        cancelButton = new JButton("鍙栨秷");
+        cancelButton.setBackground(new Color(240, 240, 240));
+        cancelButton.setForeground(Color.BLACK);
+        cancelButton.setFocusPainted(false);
+        cancelButton.setPreferredSize(new Dimension(100, 35));
+        cancelButton.addActionListener(e -> dispose());
+
+        buttonPanel.add(saveButton);
+        buttonPanel.add(cancelButton);
+
+        add(buttonPanel, BorderLayout.SOUTH);
+    }
+
+    private JPasswordField createStyledPasswordField() {
+        JPasswordField field = new JPasswordField(15);
+        field.setPreferredSize(new Dimension(200, 38)); // 璁剧疆楂樺害涓�38锛屼笌鐧诲綍椤甸潰涓�鑷�
+        field.setFont(new Font("PingFang SC", Font.PLAIN, 14));
+        field.setBorder(BorderFactory.createCompoundBorder(
+            BorderFactory.createLineBorder(new Color(200, 200, 200)),
+            BorderFactory.createEmptyBorder(8, 10, 8, 10)
+        ));
+        field.setForeground(new Color(60, 60, 60));
+        return field;
+    }
+
+    private JPanel createPasswordPanelWithEye(JPasswordField passwordField) {
+        JPanel panel = new JPanel(new BorderLayout());
+        panel.setBackground(Color.WHITE);
+        // 灏嗚竟妗嗙Щ鍔ㄥ埌 Panel 涓婏紝妯℃嫙鏂囨湰妗嗗瑙�
+        panel.setBorder(BorderFactory.createCompoundBorder(
+            BorderFactory.createLineBorder(new Color(200, 200, 200)),
+            BorderFactory.createEmptyBorder(0, 0, 0, 5)
+        ));
+        panel.setPreferredSize(new Dimension(200, 38));
+
+        // 绉婚櫎 Field 鐨勮竟妗嗭紝浣垮叾铻嶅叆 Panel
+        passwordField.setBorder(BorderFactory.createEmptyBorder(8, 10, 8, 0));
+        passwordField.setPreferredSize(null); // 璁� BorderLayout 绠$悊澶у皬
+
+        panel.add(passwordField, BorderLayout.CENTER);
+
+        JLabel eyeLabel = new JLabel();
+        eyeLabel.setPreferredSize(new Dimension(30, 38));
+        eyeLabel.setHorizontalAlignment(SwingConstants.CENTER);
+        eyeLabel.setCursor(new Cursor(Cursor.HAND_CURSOR));
+        
+        // 榛樿闂溂鍥炬爣
+        eyeLabel.setText("馃憗"); 
+        eyeLabel.setForeground(Color.GRAY);
+
+        eyeLabel.addMouseListener(new MouseAdapter() {
+            private boolean isVisible = false;
+
+            @Override
+            public void mouseClicked(MouseEvent e) {
+                isVisible = !isVisible;
+                if (isVisible) {
+                    passwordField.setEchoChar((char) 0);
+                    eyeLabel.setForeground(THEME_COLOR);
+                } else {
+                    passwordField.setEchoChar('鈥�');
+                    eyeLabel.setForeground(Color.GRAY);
+                }
+            }
+        });
+
+        panel.add(eyeLabel, BorderLayout.EAST);
+        return panel;
+    }
+
+    private void checkPasswords() {
+        String newPass = new String(newPasswordField.getPassword());
+        String confirmPass = new String(confirmPasswordField.getPassword());
+
+        // 榛樿鎻愮ず
+        if (newPass.isEmpty() && confirmPass.isEmpty()) {
+            errorLabel.setText("瀵嗙爜闀垮害涓嶈兘灏忎簬6涓瓧绗�");
+            errorLabel.setForeground(Color.GRAY);
+            return;
+        }
+
+        // 闀垮害妫�鏌�
+        if (newPass.length() > 0 && newPass.length() < 6) {
+            errorLabel.setText("瀵嗙爜闀垮害涓嶈兘灏忎簬6涓瓧绗�");
+            errorLabel.setForeground(Color.RED);
+            return;
+        }
+
+        // 涓�鑷存�ф鏌�
+        if (confirmPass.length() > 0) {
+            if (confirmPass.length() == newPass.length()) {
+                if (!newPass.equals(confirmPass)) {
+                    errorLabel.setText("涓ゆ杈撳叆鐨勬柊瀵嗙爜涓嶄竴鑷�");
+                    errorLabel.setForeground(Color.RED);
+                } else {
+                    errorLabel.setText(" "); // 瀵嗙爜涓�鑷翠笖闀垮害绗﹀悎瑕佹眰
+                }
+            } else if (confirmPass.length() < newPass.length()) {
+                // 姝e湪杈撳叆涓紝濡傛灉涔嬪墠鏈夐敊璇彁绀猴紝鍙互娓呴櫎鎴栨仮澶嶉粯璁�
+                if (newPass.length() >= 6) {
+                    errorLabel.setText(" ");
+                }
+            } else {
+                // 纭瀵嗙爜姣旀柊瀵嗙爜闀匡紝鑲畾涓嶄竴鑷�
+                errorLabel.setText("涓ゆ杈撳叆鐨勬柊瀵嗙爜涓嶄竴鑷�");
+                errorLabel.setForeground(Color.RED);
+            }
+        } else {
+            // 纭瀵嗙爜涓虹┖锛屽鏋滄柊瀵嗙爜绗﹀悎闀垮害锛屾竻闄ら敊璇紙鎴栬�呮樉绀洪粯璁ゆ彁绀猴級
+            if (newPass.length() >= 6) {
+                errorLabel.setText(" ");
+            }
+        }
+    }
+
+    private void handleSave() {
+        // 娓呴櫎涔嬪墠鐨勯敊璇俊鎭�
+        // errorLabel.setText(" "); // 涓嶅啀寮哄埗娓呴櫎锛屼緷璧� checkPasswords 鐨勭姸鎬侊紝鎴栬�呴噸鏂版鏌�
+        
+        String oldPass = new String(oldPasswordField.getPassword());
+        String newPass = new String(newPasswordField.getPassword());
+        String confirmPass = new String(confirmPasswordField.getPassword());
+
+        if (oldPass.isEmpty() || newPass.isEmpty() || confirmPass.isEmpty()) {
+            errorLabel.setText("璇峰~鍐欐墍鏈夊瓧娈�");
+            errorLabel.setForeground(Color.RED);
+            return;
+        }
+
+        if (newPass.length() < 6) {
+            errorLabel.setText("鏂板瘑鐮侀暱搴︿笉鑳藉皬浜�6涓瓧绗�");
+            errorLabel.setForeground(Color.RED);
+            return;
+        }
+
+        String currentStoredPassword = Usrdell.getProperty("password");
+        if (currentStoredPassword == null) {
+             currentStoredPassword = "";
+        }
+
+        if (!oldPass.equals(currentStoredPassword)) {
+            errorLabel.setText("鍘熷瘑鐮侀敊璇�");
+            errorLabel.setForeground(Color.RED);
+            return;
+        }
+
+        if (!newPass.equals(confirmPass)) {
+            errorLabel.setText("涓ゆ杈撳叆鐨勬柊瀵嗙爜涓嶄竴鑷�");
+            errorLabel.setForeground(Color.RED);
+            return;
+        }
+
+        // 鏇存柊瀵嗙爜
+        Usrdell.updateProperty("password", newPass);
+        JOptionPane.showMessageDialog(this, "瀵嗙爜淇敼鎴愬姛", "鎻愮ず", JOptionPane.INFORMATION_MESSAGE);
+        dispose();
+    }
+}
+

--
Gitblit v1.10.0