张世豪
2 天以前 f0d6cefec73492c29d8323e66fb92ee6bbb60cd2
src/denglu/RegistrationFrame.java
@@ -1,10 +1,16 @@
package denglu;
import ui.UIConfig;
import login.EmailCodeSender;
import login.UserRegister;
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.util.HashMap;
import java.util.Map;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
import java.util.Arrays;
public class RegistrationFrame extends JFrame {
    private JTextField userField;
@@ -16,6 +22,7 @@
    private JButton cancelButton;
    private JButton sendCodeButton;
    private JLabel userLabel, emailLabel, verificationCodeLabel, passLabel, confirmPassLabel;
    private JLabel passwordHintLabel, matchStatusLabel, emailHintLabel;
    
    // 主题颜色
    private final Color THEME_COLOR = new Color(46, 139, 87);
@@ -29,7 +36,6 @@
    // 验证码相关
    private Timer countdownTimer;
    private int countdownSeconds = 60;
    private String generatedVerificationCode;
    public RegistrationFrame(Denglu parent, String languageCode) {
        this.parentFrame = parent;
@@ -44,7 +50,8 @@
        
        // 中文翻译
        Map<String, String> zh = new HashMap<>();
        zh.put("title", "用户注册");
    zh.put("title", "用户注册");
    zh.put("window_title", "智能割草系统 - 用户注册");
        zh.put("username_label", "用户名");
        zh.put("email_label", "邮箱地址");
        zh.put("verification_code_label", "验证码");
@@ -66,7 +73,8 @@
        // 英文翻译
        Map<String, String> en = new HashMap<>();
        en.put("title", "User Registration");
    en.put("title", "User Registration");
    en.put("window_title", "Smart Mowing System - User Registration");
        en.put("username_label", "Username");
        en.put("email_label", "Email Address");
        en.put("verification_code_label", "Verification Code");
@@ -88,7 +96,8 @@
        // 西班牙语翻译
        Map<String, String> es = new HashMap<>();
        es.put("title", "Registro de Usuario");
    es.put("title", "Registro de Usuario");
    es.put("window_title", "Sistema de Corte Inteligente - Registro de Usuario");
        es.put("username_label", "Usuario");
        es.put("email_label", "Correo Electrónico");
        es.put("verification_code_label", "Código de Verificación");
@@ -110,7 +119,8 @@
        // 法语翻译
        Map<String, String> fr = new HashMap<>();
        fr.put("title", "Inscription Utilisateur");
    fr.put("title", "Inscription Utilisateur");
    fr.put("window_title", "Système de Tonte Intelligent - Inscription");
        fr.put("username_label", "Nom d'utilisateur");
        fr.put("email_label", "Adresse Email");
        fr.put("verification_code_label", "Code de Vérification");
@@ -132,7 +142,8 @@
        // 德语翻译
        Map<String, String> de = new HashMap<>();
        de.put("title", "Benutzerregistrierung");
    de.put("title", "Benutzerregistrierung");
    de.put("window_title", "Intelligentes Mähsystem - Registrierung");
        de.put("username_label", "Benutzername");
        de.put("email_label", "E-Mail-Adresse");
        de.put("verification_code_label", "Verifizierungscode");
@@ -153,10 +164,22 @@
        translations.put("de", de);
    }
    private String getTranslationValue(String languageCode, String key, String defaultValue) {
        Map<String, String> translation = translations.get(languageCode);
        if (translation != null) {
            String value = translation.get(key);
            if (value != null && !value.trim().isEmpty()) {
                return value;
            }
        }
        return defaultValue;
    }
    private void initializeUI() {
        setTitle("AutoMow - 用户注册");
    setTitle(getTranslationValue(currentLanguageCode, "window_title", "用户注册"));
        setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
        setSize(350, 500);
    setSize(UIConfig.DIALOG_WIDTH, UIConfig.DIALOG_HEIGHT);
    setMinimumSize(new Dimension(UIConfig.DIALOG_WIDTH, UIConfig.DIALOG_HEIGHT));
        setLocationRelativeTo(parentFrame);
        setResizable(false);
        
@@ -207,13 +230,23 @@
        emailLabel.setAlignmentX(Component.LEFT_ALIGNMENT);
        
        emailField = new JTextField();
        emailField.setMaximumSize(new Dimension(Integer.MAX_VALUE, 35));
        emailField.setFont(new Font("PingFang SC", Font.PLAIN, 14));
        emailField.setBorder(BorderFactory.createCompoundBorder(
            BorderFactory.createLineBorder(new Color(200, 200, 200)),
            BorderFactory.createEmptyBorder(5, 8, 5, 8)
        ));
        emailField.setAlignmentX(Component.LEFT_ALIGNMENT);
        JPanel emailContainer = new JPanel(new BorderLayout());
        emailContainer.setBackground(Color.WHITE);
        emailContainer.setMaximumSize(new Dimension(Integer.MAX_VALUE, 35));
        emailContainer.setAlignmentX(Component.LEFT_ALIGNMENT);
        emailContainer.add(emailField, BorderLayout.CENTER);
        emailHintLabel = new JLabel("");
        emailHintLabel.setFont(new Font("PingFang SC", Font.PLAIN, 12));
        emailHintLabel.setForeground(Color.RED);
        emailHintLabel.setBorder(BorderFactory.createEmptyBorder(0, 5, 0, 0));
        emailContainer.add(emailHintLabel, BorderLayout.EAST);
        
        // 验证码 - 标签左对齐
        verificationCodeLabel = new JLabel("验证码");
@@ -263,13 +296,8 @@
        passLabel.setAlignmentX(Component.LEFT_ALIGNMENT);
        
        passField = new JPasswordField();
        passField.setMaximumSize(new Dimension(Integer.MAX_VALUE, 35));
        passField.setFont(new Font("PingFang SC", Font.PLAIN, 14));
        passField.setBorder(BorderFactory.createCompoundBorder(
            BorderFactory.createLineBorder(new Color(200, 200, 200)),
            BorderFactory.createEmptyBorder(5, 8, 5, 8)
        ));
        passField.setAlignmentX(Component.LEFT_ALIGNMENT);
        JPanel passPanel = createPasswordPanel(passField);
        
        // 确认密码 - 标签左对齐
        confirmPassLabel = new JLabel("确认密码");
@@ -278,13 +306,20 @@
        confirmPassLabel.setAlignmentX(Component.LEFT_ALIGNMENT);
        
        confirmPassField = new JPasswordField();
        confirmPassField.setMaximumSize(new Dimension(Integer.MAX_VALUE, 35));
        confirmPassField.setFont(new Font("PingFang SC", Font.PLAIN, 14));
        confirmPassField.setBorder(BorderFactory.createCompoundBorder(
            BorderFactory.createLineBorder(new Color(200, 200, 200)),
            BorderFactory.createEmptyBorder(5, 8, 5, 8)
        ));
        confirmPassField.setAlignmentX(Component.LEFT_ALIGNMENT);
        JPanel confirmPassPanel = createPasswordPanel(confirmPassField);
        // 密码不一致提示
        matchStatusLabel = new JLabel(" ");
        matchStatusLabel.setFont(new Font("PingFang SC", Font.PLAIN, 12));
        matchStatusLabel.setForeground(Color.RED);
        matchStatusLabel.setAlignmentX(Component.LEFT_ALIGNMENT);
        // 密码长度提示
        passwordHintLabel = new JLabel(" ");
        passwordHintLabel.setFont(new Font("PingFang SC", Font.PLAIN, 12));
        passwordHintLabel.setForeground(Color.RED);
        passwordHintLabel.setAlignmentX(Component.LEFT_ALIGNMENT);
        
        // 注册按钮 - 单独一行,长度与文本框相同
        registerButton = new JButton("注册");
@@ -325,7 +360,7 @@
        formPanel.add(Box.createRigidArea(new Dimension(0, 10)));
        formPanel.add(emailLabel);
        formPanel.add(Box.createRigidArea(new Dimension(0, 3)));
        formPanel.add(emailField);
        formPanel.add(emailContainer);
        formPanel.add(Box.createRigidArea(new Dimension(0, 10)));
        formPanel.add(verificationCodeLabel);
        formPanel.add(Box.createRigidArea(new Dimension(0, 3)));
@@ -335,12 +370,16 @@
        formPanel.add(Box.createRigidArea(new Dimension(0, 10)));
        formPanel.add(passLabel);
        formPanel.add(Box.createRigidArea(new Dimension(0, 3)));
        formPanel.add(passField);
        formPanel.add(passPanel);
        formPanel.add(Box.createRigidArea(new Dimension(0, 10)));
        formPanel.add(confirmPassLabel);
        formPanel.add(Box.createRigidArea(new Dimension(0, 3)));
        formPanel.add(confirmPassField);
        formPanel.add(Box.createRigidArea(new Dimension(0, 20)));
        formPanel.add(confirmPassPanel);
        formPanel.add(Box.createRigidArea(new Dimension(0, 5)));
        formPanel.add(matchStatusLabel);
        formPanel.add(Box.createRigidArea(new Dimension(0, 5)));
        formPanel.add(passwordHintLabel);
        formPanel.add(Box.createRigidArea(new Dimension(0, 5)));
        formPanel.add(registerButton);
        formPanel.add(Box.createRigidArea(new Dimension(0, 8)));
        formPanel.add(cancelButton);
@@ -365,6 +404,61 @@
        
        // 回车键注册
        confirmPassField.addActionListener(e -> performRegistration());
        // 密码一致性检查
        DocumentListener matchListener = new DocumentListener() {
            private void checkMatch() {
                char[] p1 = passField.getPassword();
                char[] p2 = confirmPassField.getPassword();
                if (p2.length > 0 && p2.length == p1.length) {
                    if (!Arrays.equals(p1, p2)) {
                        matchStatusLabel.setText(getTranslationValue(currentLanguageCode, "password_mismatch_error", "两次输入的密码不一致"));
                    } else {
                        matchStatusLabel.setText(" ");
                    }
                } else {
                    matchStatusLabel.setText(" ");
                }
            }
            @Override
            public void insertUpdate(DocumentEvent e) { checkMatch(); }
            @Override
            public void removeUpdate(DocumentEvent e) { checkMatch(); }
            @Override
            public void changedUpdate(DocumentEvent e) { checkMatch(); }
        };
        confirmPassField.getDocument().addDocumentListener(matchListener);
        passField.getDocument().addDocumentListener(matchListener);
        // 密码长度检查
        passField.getDocument().addDocumentListener(new DocumentListener() {
            private void checkLength() {
                char[] password = passField.getPassword();
                if (password.length > 0 && password.length < 6) {
                     passwordHintLabel.setText(getTranslationValue(currentLanguageCode, "password_length_error", "密码长度不能少于6位"));
                } else {
                     passwordHintLabel.setText(" ");
                }
            }
            public void insertUpdate(DocumentEvent e) { checkLength(); }
            public void removeUpdate(DocumentEvent e) { checkLength(); }
            public void changedUpdate(DocumentEvent e) { checkLength(); }
        });
        // 邮箱格式检查
        emailField.getDocument().addDocumentListener(new DocumentListener() {
            private void validate() {
                String email = emailField.getText().trim();
                if (!email.isEmpty() && !isValidEmail(email)) {
                    emailHintLabel.setText(getTranslationValue(currentLanguageCode, "invalid_email_error", "邮箱格式错误"));
                } else {
                    emailHintLabel.setText("");
                }
            }
            public void insertUpdate(DocumentEvent e) { validate(); }
            public void removeUpdate(DocumentEvent e) { validate(); }
            public void changedUpdate(DocumentEvent e) { validate(); }
        });
    }
    private void updateLanguage(String languageCode) {
@@ -372,15 +466,18 @@
        
        if (translation != null) {
            // 更新所有界面文本
            setTitle("AutoMow - " + translation.get("title"));
            userLabel.setText(translation.get("username_label"));
            emailLabel.setText(translation.get("email_label"));
            verificationCodeLabel.setText(translation.get("verification_code_label"));
            passLabel.setText(translation.get("password_label"));
            confirmPassLabel.setText(translation.get("confirm_password_label"));
            registerButton.setText(translation.get("register_button"));
            cancelButton.setText(translation.get("cancel_button"));
            sendCodeButton.setText(translation.get("send_code_button"));
            setTitle(getTranslationValue(languageCode, "window_title", getTitle()));
            userLabel.setText(getTranslationValue(languageCode, "username_label", userLabel.getText()));
            emailLabel.setText(getTranslationValue(languageCode, "email_label", emailLabel.getText()));
            verificationCodeLabel.setText(getTranslationValue(languageCode, "verification_code_label", verificationCodeLabel.getText()));
            passLabel.setText(getTranslationValue(languageCode, "password_label", passLabel.getText()));
            confirmPassLabel.setText(getTranslationValue(languageCode, "confirm_password_label", confirmPassLabel.getText()));
            registerButton.setText(getTranslationValue(languageCode, "register_button", registerButton.getText()));
            cancelButton.setText(getTranslationValue(languageCode, "cancel_button", cancelButton.getText()));
            sendCodeButton.setText(getTranslationValue(languageCode, "send_code_button", sendCodeButton.getText()));
            if (passwordHintLabel != null) {
                passwordHintLabel.setText(getTranslationValue(languageCode, "password_length_error", passwordHintLabel.getText()));
            }
        }
    }
@@ -419,35 +516,51 @@
            return;
        }
        
        // 生成随机验证码(实际应用中应该通过邮件发送)
        generatedVerificationCode = generateRandomCode();
        // 禁用按钮,防止重复点击
        sendCodeButton.setEnabled(false);
        
        // 在实际应用中,这里应该调用邮件发送服务
        // 这里仅模拟发送过程
        System.out.println("验证码 " + generatedVerificationCode + " 已发送到 " + email);
        // 获取当前语言的翻译
        Map<String, String> translationMap = translations.get(currentLanguageCode);
        if (translationMap != null) {
            JOptionPane.showMessageDialog(this,
                translationMap.get("verification_code_sent"),
                "提示",
                JOptionPane.INFORMATION_MESSAGE);
        } else {
            JOptionPane.showMessageDialog(this,
                "验证码已发送到您的邮箱",
                "提示",
                JOptionPane.INFORMATION_MESSAGE);
        }
        // 开始倒计时
        startCountdown();
    }
    // 生成随机验证码
    private String generateRandomCode() {
        // 生成6位随机数字
        return String.valueOf((int)((Math.random() * 9 + 1) * 100000));
        // 在新线程中调用API,避免阻塞UI
        new Thread(() -> {
            try {
                // 调用邮件验证码发送API
                EmailCodeSender.EmailCodeResponse response = EmailCodeSender.sendEmailCode(email);
                // 在EDT线程中更新UI
                SwingUtilities.invokeLater(() -> {
                    if (response.isSuccess()) {
                        // 发送成功,显示提示并开始倒计时
                        Map<String, String> translationMap = translations.get(currentLanguageCode);
                        String successMessage = translationMap != null ?
                            translationMap.get("verification_code_sent") : "验证码已发送到您的邮箱";
                        JOptionPane.showMessageDialog(this,
                            successMessage,
                            "提示",
                            JOptionPane.INFORMATION_MESSAGE);
                        // 开始60秒倒计时
                        startCountdown();
                    } else {
                        // 发送失败,显示错误信息并恢复按钮
                        sendCodeButton.setEnabled(true);
                        String errorMessage = response.getMessage() != null ?
                            response.getMessage() : "验证码发送失败";
                        JOptionPane.showMessageDialog(this,
                            errorMessage,
                            "错误",
                            JOptionPane.ERROR_MESSAGE);
                    }
                });
            } catch (Exception e) {
                // 异常处理,恢复按钮并显示错误
                SwingUtilities.invokeLater(() -> {
                    sendCodeButton.setEnabled(true);
                    JOptionPane.showMessageDialog(this,
                        "发送验证码时发生错误: " + e.getMessage(),
                        "错误",
                        JOptionPane.ERROR_MESSAGE);
                });
            }
        }).start();
    }
    
    // 开始倒计时
@@ -488,17 +601,19 @@
    }
    private void performRegistration() {
        String username = userField.getText().trim();
        String nickname = userField.getText().trim();
        String email = emailField.getText().trim();
        String verificationCode = verificationCodeField.getText().trim();
        String password = new String(passField.getPassword());
        String confirmPassword = new String(confirmPassField.getPassword());
        String code = verificationCodeField.getText().trim();
        // 获取密码字段的值(与登录页面保持一致的处理方式)
        String password = new String(passField.getPassword()).trim();
        String confirmPassword = new String(confirmPassField.getPassword()).trim();
        
        // 获取当前语言的翻译
        Map<String, String> translationMap = translations.get(currentLanguageCode);
        
        // 输入验证
        if (username.isEmpty() || email.isEmpty() || verificationCode.isEmpty() ||
        if (nickname.isEmpty() || email.isEmpty() || code.isEmpty() ||
            password.isEmpty() || confirmPassword.isEmpty()) {
            String errorMessage = translationMap != null ? 
                translationMap.get("empty_fields_error") : "请填写所有字段";
@@ -535,19 +650,7 @@
            return;
        }
        
        // 验证验证码
        if (!verificationCode.equals(generatedVerificationCode)) {
            String errorMessage = translationMap != null ?
                translationMap.get("invalid_verification_code") : "验证码错误";
            JOptionPane.showMessageDialog(this,
                errorMessage,
                "输入错误",
                JOptionPane.WARNING_MESSAGE);
            verificationCodeField.setText("");
            verificationCodeField.requestFocus();
            return;
        }
        // 验证两次输入的密码是否一致
        if (!password.equals(confirmPassword)) {
            String errorMessage = translationMap != null ? 
                translationMap.get("password_mismatch_error") : "两次输入的密码不一致";
@@ -561,25 +664,51 @@
            return;
        }
        
        // 保存用户信息
        UserChuShiHua.updateProperty("userName", username);
        UserChuShiHua.updateProperty("email", email);
        UserChuShiHua.updateProperty("password", password);
        // 禁用注册按钮,防止重复提交
        registerButton.setEnabled(false);
        
        String successMessage = translationMap != null ?
            translationMap.get("success_message") : "注册成功!";
        JOptionPane.showMessageDialog(this,
            successMessage,
            "成功",
            JOptionPane.INFORMATION_MESSAGE);
        dispose();
        // 自动填充登录表单
        if (parentFrame != null) {
            // 这里需要访问父窗口的usernameField,但由于封装性,我们可能需要添加公共方法
            // 暂时留空,可以根据需要实现
        }
        // 在新线程中调用API,避免阻塞UI
        new Thread(() -> {
            try {
                // 调用用户注册API
                UserRegister.RegisterResponse response = UserRegister.register(email, password, code, nickname,confirmPassword);
                // 在EDT线程中更新UI
                SwingUtilities.invokeLater(() -> {
                    registerButton.setEnabled(true);
                    if (response.isSuccess()) {
                        // 注册成功,显示成功提示
                        String successMessage = translationMap != null ?
                            translationMap.get("success_message") : "注册成功!";
                        JOptionPane.showMessageDialog(this,
                            successMessage,
                            "成功",
                            JOptionPane.INFORMATION_MESSAGE);
                        // 关闭注册窗口
                        dispose();
                    } else {
                        // 注册失败,显示错误信息
                        String errorMessage = response.getMessage() != null ?
                            response.getMessage() : "注册失败";
                        JOptionPane.showMessageDialog(this,
                            errorMessage,
                            "注册失败",
                            JOptionPane.ERROR_MESSAGE);
                    }
                });
            } catch (Exception e) {
                // 异常处理,恢复按钮并显示错误
                SwingUtilities.invokeLater(() -> {
                    registerButton.setEnabled(true);
                    JOptionPane.showMessageDialog(this,
                        "注册时发生错误: " + e.getMessage(),
                        "错误",
                        JOptionPane.ERROR_MESSAGE);
                });
            }
        }).start();
    }
    
    @Override
@@ -590,4 +719,47 @@
        }
        super.dispose();
    }
    private JPanel createPasswordPanel(JPasswordField passField) {
        JPanel panel = new JPanel(new BorderLayout());
        panel.setBackground(Color.WHITE);
        panel.setBorder(BorderFactory.createCompoundBorder(
            BorderFactory.createLineBorder(new Color(200, 200, 200)),
            BorderFactory.createEmptyBorder(1, 1, 1, 1)
        ));
        panel.setMaximumSize(new Dimension(Integer.MAX_VALUE, 35));
        panel.setAlignmentX(Component.LEFT_ALIGNMENT);
        passField.setBorder(BorderFactory.createEmptyBorder(4, 8, 4, 8));
        panel.add(passField, BorderLayout.CENTER);
        JButton toggleBtn = new JButton();
        try {
            ImageIcon icon = new ImageIcon("image/look.png");
            if (icon.getIconWidth() > 0) {
                Image img = icon.getImage().getScaledInstance(20, 20, Image.SCALE_SMOOTH);
                toggleBtn.setIcon(new ImageIcon(img));
            } else {
                toggleBtn.setText("👁");
            }
        } catch (Exception e) {
            toggleBtn.setText("👁");
        }
        toggleBtn.setBorder(BorderFactory.createEmptyBorder(0, 5, 0, 5));
        toggleBtn.setContentAreaFilled(false);
        toggleBtn.setFocusPainted(false);
        toggleBtn.setCursor(new Cursor(Cursor.HAND_CURSOR));
        toggleBtn.addActionListener(e -> {
            if (passField.getEchoChar() != 0) {
                passField.setEchoChar((char) 0);
            } else {
                passField.setEchoChar('•');
            }
        });
        panel.add(toggleBtn, BorderLayout.EAST);
        return panel;
    }
}