张世豪
2 天以前 0e77cd7385ea6a55c2a8583600abdf53c781cdf5
新增了找回密码功能
已修改4个文件
已添加1个文件
471 ■■■■■ 文件已修改
set.properties 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/denglu/Denglu.java 33 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/set/Sets.java 60 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/user/ZhaohuiMima.java 370 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
user.properties 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
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
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 {
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;
/**
 * è®¾ç½®å¯¹è¯æ¡† - å‚考Shouye.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;
    }
}
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)); // å®½åº¦ç”±GridBagLayout控制,高度设为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;
    }
}
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