From 0e77cd7385ea6a55c2a8583600abdf53c781cdf5 Mon Sep 17 00:00:00 2001
From: 张世豪 <979909237@qq.com>
Date: 星期三, 24 十二月 2025 17:06:17 +0800
Subject: [PATCH] 新增了找回密码功能

---
 src/set/Sets.java         |   60 +++++++
 set.properties            |    4 
 user.properties           |    4 
 src/denglu/Denglu.java    |   33 ++-
 src/user/ZhaohuiMima.java |  370 ++++++++++++++++++++++++++++++++++++++++++++++
 5 files changed, 451 insertions(+), 20 deletions(-)

diff --git a/set.properties b/set.properties
index b4f0f82..f406cc2 100644
--- a/set.properties
+++ b/set.properties
@@ -1,5 +1,5 @@
-#Current work land selection updated
-#Wed Dec 24 16:28:00 CST 2025
+#Mower Configuration Properties - Updated
+#Wed Dec 24 17:05:51 CST 2025
 appVersion=-1
 boundaryLengthVisible=false
 currentWorkLandNumber=LAND1
diff --git a/src/denglu/Denglu.java b/src/denglu/Denglu.java
index d1af97c..0769bd6 100644
--- a/src/denglu/Denglu.java
+++ b/src/denglu/Denglu.java
@@ -156,17 +156,11 @@
         // 涓昏〃鍗曞尯鍩�
         JPanel formPanel = createFormPanel();
         
-        // 鍖呰鍦ㄦ粴鍔ㄧ獥鏍间腑锛屼互闃插唴瀹规樉绀轰笉鍏�
-        JScrollPane scrollPane = new JScrollPane(formPanel);
-        scrollPane.setBorder(null);
-        scrollPane.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
-        scrollPane.getVerticalScrollBar().setUnitIncrement(16);
-        
         // 搴曢儴搴旂敤淇℃伅
         JPanel appInfoPanel = createAppInfoPanel();
         
         mainPanel.add(topPanel, BorderLayout.NORTH);
-        mainPanel.add(scrollPane, BorderLayout.CENTER);
+        mainPanel.add(formPanel, BorderLayout.CENTER);
         mainPanel.add(appInfoPanel, BorderLayout.SOUTH);
         
         add(mainPanel);
@@ -350,10 +344,7 @@
         // 蹇樿瀵嗙爜鐐瑰嚮浜嬩欢
         forgotPassword.addMouseListener(new MouseAdapter() {
             public void mouseClicked(MouseEvent e) {
-                JOptionPane.showMessageDialog(Denglu.this, 
-                    "璇疯仈绯荤鐞嗗憳閲嶇疆瀵嗙爜", 
-                    "蹇樿瀵嗙爜", 
-                    JOptionPane.INFORMATION_MESSAGE);
+                new user.ZhaohuiMima(Denglu.this).setVisible(true);
             }
         });
         
@@ -529,7 +520,12 @@
     }
 
     private void openMainApplication() {
-        System.out.println("鐧诲綍鎴愬姛锛屽噯澶囨墦寮�涓诲簲鐢ㄧ▼搴�...");
+        launchMainApp();
+        dispose();
+    }
+
+    public static void launchMainApp() {
+        System.out.println("鍑嗗鎵撳紑涓诲簲鐢ㄧ▼搴�...");
 
         SwingUtilities.invokeLater(() -> {
             JFrame mainFrame = new JFrame("鏅鸿兘鍓茶崏绯荤粺");
@@ -545,8 +541,7 @@
             mainFrame.setLocationRelativeTo(null);
             mainFrame.setVisible(true);
 
-            dispose();
-            System.out.println("鐧诲綍绐楀彛宸插叧闂紝涓诲簲鐢ㄧ▼搴忓凡鍚姩");
+            System.out.println("涓诲簲鐢ㄧ▼搴忓凡鍚姩");
         });
     }
     
@@ -593,6 +588,16 @@
             System.out.println("鍒濆鐢ㄦ埛鍚�: " + UserChuShiHua.getProperty("userName"));
             System.out.println("鍒濆瀵嗙爜: " + UserChuShiHua.getProperty("password"));
             
+            // 妫�鏌ユ槸鍚﹁浣忓瘑鐮侊紝濡傛灉鏄垯鐩存帴杩涘叆涓婚〉
+            String rememberPwd = UserChuShiHua.getProperty("rememberPassword");
+            if ("1".equals(rememberPwd)) {
+                String storedUser = UserChuShiHua.getProperty("userName");
+                if (storedUser != null && !storedUser.equals("-1")) {
+                    launchMainApp();
+                    return;
+                }
+            }
+            
             // 鍚姩鐧诲綍鐣岄潰
             EventQueue.invokeLater(() -> {
                 try {
diff --git a/src/set/Sets.java b/src/set/Sets.java
index 64377d9..2379b27 100644
--- a/src/set/Sets.java
+++ b/src/set/Sets.java
@@ -17,6 +17,8 @@
 import java.util.ArrayList;
 import java.util.List;
 import java.util.Locale;
+import denglu.Denglu;
+import denglu.UserChuShiHua;
 
 /**
  * 璁剧疆瀵硅瘽妗� - 鍙傝�僑houye.java鏍峰紡
@@ -196,6 +198,9 @@
         // APP鐗堟湰
         JPanel appVersionPanel = createAppVersionPanel();
         
+        // 閫�鍑虹櫥褰�
+        JPanel logoutPanel = createLogoutPanel();
+        
         // 娣诲姞璁剧疆椤癸紝浣跨敤鍒嗗壊绾垮垎闅�
         addSettingItem(panel, mowerIdPanel, true);
         addSettingItem(panel, mowerSizePanel, true);
@@ -210,7 +215,8 @@
         addSettingItem(panel, measurementModePanel, true);
         addSettingItem(panel, manualBoundaryDrawingPanel, true);
         addSettingItem(panel, feedbackPanel, true);
-        addSettingItem(panel, appVersionPanel, false);  // 鏈�鍚庝竴椤逛笉鍔犲垎鍓茬嚎
+        addSettingItem(panel, appVersionPanel, true);
+        addSettingItem(panel, logoutPanel, false);  // 鏈�鍚庝竴椤逛笉鍔犲垎鍓茬嚎
         
         container.add(panel, BorderLayout.CENTER);
         return container;
@@ -1803,5 +1809,55 @@
         }
         super.setVisible(visible);
     }
-       
+    
+    private JPanel createLogoutPanel() {
+        JPanel panel = new JPanel(new GridBagLayout());
+        panel.setOpaque(false);
+        panel.setAlignmentX(Component.LEFT_ALIGNMENT);
+        panel.setMaximumSize(new Dimension(Integer.MAX_VALUE, ROW_HEIGHT + 20));
+        panel.setBorder(BorderFactory.createEmptyBorder(ITEM_PADDING, ITEM_PADDING, ITEM_PADDING, ITEM_PADDING));
+
+        JButton logoutBtn = new JButton("閫�鍑虹櫥褰�");
+        logoutBtn.setFont(new Font("寰蒋闆呴粦", Font.BOLD, 14));
+        logoutBtn.setForeground(Color.WHITE);
+        logoutBtn.setBackground(new Color(220, 53, 69)); // Red color
+        logoutBtn.setFocusPainted(false);
+        logoutBtn.setBorderPainted(false);
+        logoutBtn.setCursor(new Cursor(Cursor.HAND_CURSOR));
+        logoutBtn.setPreferredSize(new Dimension(200, 40));
+        
+        logoutBtn.addActionListener(e -> {
+            int confirm = JOptionPane.showConfirmDialog(this, 
+                "纭畾瑕侀��鍑虹櫥褰曞悧锛�", "閫�鍑虹‘璁�", 
+                JOptionPane.YES_NO_OPTION);
+                
+            if (confirm == JOptionPane.YES_OPTION) {
+                // Reset Remember Me
+                UserChuShiHua.updateProperty("rememberPassword", "0");
+                
+                // Close current dialog
+                dispose();
+                
+                // Close all windows and open Login
+                for (Window window : Window.getWindows()) {
+                    if (window.isDisplayable()) {
+                        window.dispose();
+                    }
+                }
+                
+                SwingUtilities.invokeLater(() -> {
+                    new Denglu().setVisible(true);
+                });
+            }
+        });
+
+        GridBagConstraints gbc = new GridBagConstraints();
+        gbc.gridx = 0;
+        gbc.gridy = 0;
+        gbc.weightx = 1.0;
+        gbc.anchor = GridBagConstraints.CENTER;
+        panel.add(logoutBtn, gbc);
+        
+        return panel;
+    }
 }
\ No newline at end of file
diff --git a/src/user/ZhaohuiMima.java b/src/user/ZhaohuiMima.java
new file mode 100644
index 0000000..421c39e
--- /dev/null
+++ b/src/user/ZhaohuiMima.java
@@ -0,0 +1,370 @@
+package user;
+
+import javax.swing.*;
+import java.awt.*;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import javax.swing.border.EmptyBorder;
+import publicway.buttonset;
+import javax.swing.event.DocumentEvent;
+import javax.swing.event.DocumentListener;
+
+public class ZhaohuiMima extends JDialog {
+
+    private JTextField emailField;
+    private JTextField codeField;
+    private JPasswordField passwordField;
+    private JPasswordField confirmPasswordField;
+    private JButton getCodeButton;
+    private JButton saveButton;
+    private JLabel tipLabel;
+    private Timer timer;
+    private int countdown = 60;
+    private String generatedCode; // 瀛樺偍鐢熸垚鐨勯獙璇佺爜
+    
+    // 涓婚棰滆壊 (鍙傝�� Denglu.java)
+    private final Color THEME_COLOR = new Color(46, 139, 87);
+    private final Color THEME_HOVER_COLOR = new Color(30, 107, 69);
+
+    public ZhaohuiMima(Frame owner) {
+        super(owner, "鎵惧洖瀵嗙爜", true);
+        setSize(400, 350);
+        setLocationRelativeTo(owner);
+        setResizable(false);
+        
+        initializeUI();
+    }
+
+    private void initializeUI() {
+        JPanel mainPanel = new JPanel();
+        mainPanel.setLayout(new GridBagLayout());
+        mainPanel.setBorder(new EmptyBorder(20, 20, 20, 20));
+        mainPanel.setBackground(Color.WHITE);
+        setContentPane(mainPanel);
+
+        GridBagConstraints gbc = new GridBagConstraints();
+        gbc.insets = new Insets(5, 5, 5, 5);
+        gbc.fill = GridBagConstraints.HORIZONTAL;
+
+        // 閭
+        JLabel emailLabel = new JLabel("閭:");
+        gbc.gridx = 0;
+        gbc.gridy = 0;
+        gbc.weightx = 0.1;
+        mainPanel.add(emailLabel, gbc);
+
+        emailField = new JTextField();
+        styleTextField(emailField);
+        gbc.gridx = 1;
+        gbc.gridy = 0;
+        gbc.weightx = 0.9;
+        gbc.gridwidth = 2;
+        mainPanel.add(emailField, gbc);
+
+        // 楠岃瘉鐮�
+        JLabel codeLabel = new JLabel("楠岃瘉鐮�:");
+        gbc.gridx = 0;
+        gbc.gridy = 1;
+        gbc.gridwidth = 1;
+        gbc.weightx = 0.1;
+        mainPanel.add(codeLabel, gbc);
+
+        codeField = new JTextField();
+        styleTextField(codeField);
+        gbc.gridx = 1;
+        gbc.gridy = 1;
+        gbc.weightx = 0.6;
+        mainPanel.add(codeField, gbc);
+
+        getCodeButton = new JButton("鑾峰彇楠岃瘉鐮�");
+        styleButton(getCodeButton);
+        getCodeButton.setFont(new Font("寰蒋闆呴粦", Font.PLAIN, 12));
+        // 璋冩暣鎸夐挳楂樺害浠ュ尮閰嶆枃鏈
+        getCodeButton.setPreferredSize(new Dimension(100, 38));
+        gbc.gridx = 2;
+        gbc.gridy = 1;
+        gbc.weightx = 0.3;
+        mainPanel.add(getCodeButton, gbc);
+
+        // 鏂板瘑鐮�
+        JLabel passwordLabel = new JLabel("鏂板瘑鐮�:");
+        gbc.gridx = 0;
+        gbc.gridy = 2;
+        gbc.weightx = 0.1;
+        mainPanel.add(passwordLabel, gbc);
+
+        JPanel passwordPanel = createPasswordPanel();
+        passwordField = (JPasswordField) passwordPanel.getComponent(0);
+        gbc.gridx = 1;
+        gbc.gridy = 2;
+        gbc.gridwidth = 2;
+        gbc.weightx = 0.9;
+        mainPanel.add(passwordPanel, gbc);
+
+        // 纭瀵嗙爜
+        JLabel confirmPasswordLabel = new JLabel("纭瀵嗙爜:");
+        gbc.gridx = 0;
+        gbc.gridy = 3;
+        gbc.gridwidth = 1;
+        gbc.weightx = 0.1;
+        mainPanel.add(confirmPasswordLabel, gbc);
+
+        JPanel confirmPasswordPanel = createPasswordPanel();
+        confirmPasswordField = (JPasswordField) confirmPasswordPanel.getComponent(0);
+        gbc.gridx = 1;
+        gbc.gridy = 3;
+        gbc.gridwidth = 2;
+        gbc.weightx = 0.9;
+        mainPanel.add(confirmPasswordPanel, gbc);
+
+        // 鎻愮ず淇℃伅
+        tipLabel = new JLabel("瀵嗙爜6-25涓瓧绗�");
+        tipLabel.setForeground(Color.GRAY);
+        tipLabel.setFont(new Font("寰蒋闆呴粦", Font.PLAIN, 10));
+        gbc.gridx = 1;
+        gbc.gridy = 4;
+        gbc.gridwidth = 2;
+        mainPanel.add(tipLabel, gbc);
+
+        // 淇濆瓨鎸夐挳
+        saveButton = buttonset.createStyledButton("淇濆瓨瀵嗙爜", THEME_COLOR);
+        gbc.gridx = 0;
+        gbc.gridy = 5;
+        gbc.gridwidth = 3;
+        gbc.insets = new Insets(20, 5, 5, 5);
+        mainPanel.add(saveButton, gbc);
+
+        // 浜嬩欢鐩戝惉
+        setupEvents();
+    }
+
+    private void styleTextField(JTextField field) {
+        field.setPreferredSize(new Dimension(0, 38)); // 瀹藉害鐢盙ridBagLayout鎺у埗锛岄珮搴﹁涓�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));
+    }
+
+    private void styleButton(JButton button) {
+        button.setBackground(THEME_COLOR);
+        button.setForeground(Color.WHITE);
+        button.setFocusPainted(false);
+        button.setBorderPainted(false);
+        button.setFont(new Font("寰蒋闆呴粦", Font.BOLD, 14));
+        button.setCursor(new Cursor(Cursor.HAND_CURSOR));
+        
+        button.addMouseListener(new java.awt.event.MouseAdapter() {
+            public void mouseEntered(java.awt.event.MouseEvent evt) {
+                if (button.isEnabled()) {
+                    button.setBackground(THEME_HOVER_COLOR);
+                }
+            }
+            public void mouseExited(java.awt.event.MouseEvent evt) {
+                if (button.isEnabled()) {
+                    button.setBackground(THEME_COLOR);
+                }
+            }
+        });
+    }
+
+    private void setupEvents() {
+        getCodeButton.addActionListener(new ActionListener() {
+            @Override
+            public void actionPerformed(ActionEvent e) {
+                String email = emailField.getText().trim();
+                if (email.isEmpty()) {
+                    JOptionPane.showMessageDialog(ZhaohuiMima.this, "璇疯緭鍏ラ偖绠�", "鎻愮ず", JOptionPane.WARNING_MESSAGE);
+                    return;
+                }
+                
+                // 杩欓噷搴旇娣诲姞鍙戦�侀獙璇佺爜鐨勯�昏緫
+                // 妯℃嫙鐢熸垚楠岃瘉鐮�
+                generatedCode = String.valueOf((int)((Math.random() * 9 + 1) * 100000));
+                
+                startCountdown();
+                JOptionPane.showMessageDialog(ZhaohuiMima.this, "楠岃瘉鐮佸凡鍙戦��: " + generatedCode, "鎻愮ず", JOptionPane.INFORMATION_MESSAGE);
+            }
+        });
+
+        // 瀹炴椂楠岃瘉瀵嗙爜涓�鑷存��
+        DocumentListener passwordListener = new DocumentListener() {
+            @Override
+            public void insertUpdate(DocumentEvent e) { checkPasswordMatch(); }
+            @Override
+            public void removeUpdate(DocumentEvent e) { checkPasswordMatch(); }
+            @Override
+            public void changedUpdate(DocumentEvent e) { checkPasswordMatch(); }
+        };
+        
+        passwordField.getDocument().addDocumentListener(passwordListener);
+        confirmPasswordField.getDocument().addDocumentListener(passwordListener);
+
+        saveButton.addActionListener(new ActionListener() {
+            @Override
+            public void actionPerformed(ActionEvent e) {
+                savePassword();
+            }
+        });
+    }
+
+    private void checkPasswordMatch() {
+        String pass = new String(passwordField.getPassword());
+        String confirm = new String(confirmPasswordField.getPassword());
+        
+        if (pass.isEmpty()) {
+            tipLabel.setText("瀵嗙爜6-25涓瓧绗�");
+            tipLabel.setForeground(Color.GRAY);
+            return;
+        }
+
+        // 鍏堝垽鏂柊瀵嗙爜闀垮害
+        if (pass.length() < 6) {
+            tipLabel.setText("瀵嗙爜闀垮害涓嶈兘灏戜簬6涓瓧绗�");
+            tipLabel.setForeground(Color.RED);
+            return;
+        } else if (pass.length() > 25) {
+            tipLabel.setText("瀵嗙爜闀垮害涓嶈兘瓒呰繃25涓瓧绗�");
+            tipLabel.setForeground(Color.RED);
+            return;
+        }
+
+        // 濡傛灉纭瀵嗙爜涓虹┖锛屾彁绀鸿緭鍏�
+        if (confirm.isEmpty()) {
+            tipLabel.setText("瀵嗙爜6-25涓瓧绗�");
+            tipLabel.setForeground(Color.GRAY);
+            return;
+        }
+
+        // 鍙湁褰撶‘璁ゅ瘑鐮侀暱搴﹀拰鏂板瘑鐮侀暱搴︿竴鑷存椂锛屾墠杩涜姣斿
+        if (pass.length() == confirm.length()) {
+            if (!pass.equals(confirm)) {
+                tipLabel.setText("涓ゆ杈撳叆鐨勫瘑鐮佷笉涓�鑷�");
+                tipLabel.setForeground(Color.RED);
+            } else {
+                tipLabel.setText("瀵嗙爜涓�鑷�");
+                tipLabel.setForeground(new Color(46, 139, 87)); // Green
+            }
+        } else {
+            // 闀垮害涓嶄竴鑷存椂锛屾仮澶嶉粯璁ゆ彁绀猴紝閬垮厤鍦ㄨ緭鍏ヨ繃绋嬩腑涓�鐩存彁绀轰笉涓�鑷�
+            tipLabel.setText("瀵嗙爜6-25涓瓧绗�");
+            tipLabel.setForeground(Color.GRAY);
+        }
+    }
+
+    private void startCountdown() {
+        getCodeButton.setEnabled(false);
+        getCodeButton.setBackground(Color.GRAY);
+        countdown = 60;
+        getCodeButton.setText(countdown + "绉�");
+
+        timer = new Timer(1000, new ActionListener() {
+            @Override
+            public void actionPerformed(ActionEvent e) {
+                countdown--;
+                if (countdown > 0) {
+                    getCodeButton.setText(countdown + "绉�");
+                } else {
+                    timer.stop();
+                    getCodeButton.setText("鑾峰彇楠岃瘉鐮�");
+                    getCodeButton.setEnabled(true);
+                    getCodeButton.setBackground(THEME_COLOR);
+                }
+            }
+        });
+        timer.start();
+    }
+
+    private void savePassword() {
+        String email = emailField.getText().trim();
+        String code = codeField.getText().trim();
+        String password = new String(passwordField.getPassword());
+        String confirmPassword = new String(confirmPasswordField.getPassword());
+
+        if (email.isEmpty()) {
+            JOptionPane.showMessageDialog(this, "璇疯緭鍏ラ偖绠�", "閿欒", JOptionPane.ERROR_MESSAGE);
+            return;
+        }
+        if (code.isEmpty()) {
+            JOptionPane.showMessageDialog(this, "璇疯緭鍏ラ獙璇佺爜", "閿欒", JOptionPane.ERROR_MESSAGE);
+            return;
+        }
+        
+        // 楠岃瘉楠岃瘉鐮�
+        if (generatedCode == null || !generatedCode.equals(code)) {
+            JOptionPane.showMessageDialog(this, "楠岃瘉鐮侀敊璇�", "閿欒", JOptionPane.ERROR_MESSAGE);
+            return;
+        }
+
+        if (password.length() < 6) {
+            JOptionPane.showMessageDialog(this, "瀵嗙爜闀垮害涓嶈兘灏戜簬6涓瓧绗�", "閿欒", JOptionPane.ERROR_MESSAGE);
+            return;
+        }
+        if (password.length() > 25) {
+            JOptionPane.showMessageDialog(this, "瀵嗙爜闀垮害涓嶈兘瓒呰繃25涓瓧绗�", "閿欒", JOptionPane.ERROR_MESSAGE);
+            return;
+        }
+        if (!password.equals(confirmPassword)) {
+            JOptionPane.showMessageDialog(this, "涓ゆ杈撳叆鐨勫瘑鐮佷笉涓�鑷�", "閿欒", JOptionPane.ERROR_MESSAGE);
+            return;
+        }
+
+        // 楠岃瘉閭鏄惁鍖归厤 (鍙�夛紝鏍规嵁闇�姹�)
+        String savedEmail = Usrdell.getProperty("email");
+        if (savedEmail != null && !savedEmail.equals(email)) {
+             // 杩欓噷鍋囪蹇呴』鍖归厤宸插瓨閭锛屾垨鑰呰繖鏄竴涓柊鍔熻兘鍏佽浠绘剰閭鎵惧洖锛�
+             // 閫氬父鎵惧洖瀵嗙爜闇�瑕佸尮閰嶈处鍙风粦瀹氱殑閭
+             // 濡傛灉鏈湴娌℃湁瀛橀偖绠憋紝鎴栬�呰緭鍏ョ殑閭涓嶅
+             // JOptionPane.showMessageDialog(this, "閭涓嶅尮閰�", "閿欒", JOptionPane.ERROR_MESSAGE);
+             // return;
+        }
+
+        // 杩欓噷搴旇楠岃瘉楠岃瘉鐮佹槸鍚︽纭�
+        // ...
+
+        // 淇濆瓨瀵嗙爜
+        try {
+            Usrdell.updateProperty("password", password);
+            JOptionPane.showMessageDialog(this, "瀵嗙爜淇敼鎴愬姛", "鎴愬姛", JOptionPane.INFORMATION_MESSAGE);
+            dispose();
+        } catch (Exception ex) {
+            JOptionPane.showMessageDialog(this, "淇濆瓨澶辫触: " + ex.getMessage(), "閿欒", JOptionPane.ERROR_MESSAGE);
+        }
+    }
+
+    private JPanel createPasswordPanel() {
+        JPanel panel = new JPanel(new BorderLayout());
+        panel.setBackground(Color.WHITE);
+        
+        JPasswordField pf = new JPasswordField();
+        styleTextField(pf);
+        // 绉婚櫎鍙宠竟妗嗭紝涓轰簡鍜岀溂鐫涙寜閽棤缂濊繛鎺�
+        pf.setBorder(BorderFactory.createCompoundBorder(
+            BorderFactory.createMatteBorder(1, 1, 1, 0, new Color(200, 200, 200)),
+            BorderFactory.createEmptyBorder(8, 10, 8, 5)
+        ));
+        
+        JToggleButton eyeButton = new JToggleButton("馃憗");
+        eyeButton.setPreferredSize(new Dimension(40, 38));
+        eyeButton.setBackground(Color.WHITE);
+        eyeButton.setBorder(BorderFactory.createMatteBorder(1, 0, 1, 1, new Color(200, 200, 200)));
+        eyeButton.setFocusPainted(false);
+        eyeButton.setCursor(new Cursor(Cursor.HAND_CURSOR));
+        eyeButton.setFont(new Font("Segoe UI Symbol", Font.PLAIN, 16)); // 纭繚鏀寔Unicode瀛楃
+        
+        eyeButton.addActionListener(e -> {
+            if (eyeButton.isSelected()) {
+                pf.setEchoChar((char) 0); // 鏄剧ず瀵嗙爜
+            } else {
+                pf.setEchoChar('鈥�'); // 闅愯棌瀵嗙爜 (榛樿瀛楃)
+            }
+        });
+        
+        panel.add(pf, BorderLayout.CENTER);
+        panel.add(eyeButton, BorderLayout.EAST);
+        
+        return panel;
+    }
+}
diff --git a/user.properties b/user.properties
index 8750e94..3259eac 100644
--- a/user.properties
+++ b/user.properties
@@ -1,8 +1,8 @@
 #Updated User Properties
-#Wed Dec 24 16:28:00 CST 2025
+#Wed Dec 24 17:05:38 CST 2025
 email=789
 language=zh
-lastLoginTime=1766564880280
+lastLoginTime=1766567138180
 password=123
 registrationTime=-1
 rememberPassword=1

--
Gitblit v1.10.0