From dba7308800d28ce01e4409767be8648f60720009 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=A8=E6=8D=B7?= <2747764757@qq.com> Date: Sat, 11 Oct 2025 22:26:11 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E6=94=B9MathLearningApp.java?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/MathLearningApp.java | 1549 ++++++++++++++++++++------------------ 1 file changed, 818 insertions(+), 731 deletions(-) diff --git a/src/MathLearningApp.java b/src/MathLearningApp.java index 48a28b6..1298f76 100644 --- a/src/MathLearningApp.java +++ b/src/MathLearningApp.java @@ -6,7 +6,12 @@ public class MathLearningApp { private JFrame mainFrame; private UserManager userManager; private QuizController quizController; - private UserManager.User currentUser; + + // 使用新的数据模型 + private ViewData viewData; + private AppController appController; + private ViewBuilder viewBuilder; + private EventHandlers eventHandlers; private static final String SYSTEM_EMAIL_HOST = "smtp.qq.com"; private static final String SYSTEM_EMAIL_PORT = "587"; @@ -31,835 +36,917 @@ public class MathLearningApp { mainFrame.setSize(500, 550); mainFrame.setLocationRelativeTo(null); + // 初始化MVC组件 + initializeMVCComponents(); + showLoginView(); mainFrame.setVisible(true); } - // 登录界面 - 完全保持不变 - private void showLoginView() { - JPanel mainPanel = new JPanel(); - mainPanel.setLayout(new BoxLayout(mainPanel, BoxLayout.Y_AXIS)); - mainPanel.setBorder(BorderFactory.createEmptyBorder(30, 30, 30, 30)); - - JLabel titleLabel = new JLabel("数学学习软件 - 登录"); - titleLabel.setFont(new Font("微软雅黑", Font.BOLD, 20)); - titleLabel.setAlignmentX(Component.CENTER_ALIGNMENT); - - JPanel inputPanel = new JPanel(); - inputPanel.setLayout(new BoxLayout(inputPanel, BoxLayout.Y_AXIS)); - inputPanel.setAlignmentX(Component.CENTER_ALIGNMENT); - - JPanel emailPanel = new JPanel(new FlowLayout(FlowLayout.LEFT)); - JLabel emailLabel = new JLabel("邮箱:"); - JTextField emailField = new JTextField(20); - emailField.setPreferredSize(new Dimension(200, 30)); - emailPanel.add(emailLabel); - emailPanel.add(emailField); - - JPanel passwordPanel = new JPanel(new FlowLayout(FlowLayout.LEFT)); - JLabel passwordLabel = new JLabel("密码:"); - JPasswordField passwordField = new JPasswordField(20); - passwordField.setPreferredSize(new Dimension(200, 30)); - passwordPanel.add(passwordLabel); - passwordPanel.add(passwordField); - - inputPanel.add(emailPanel); - inputPanel.add(Box.createVerticalStrut(15)); - inputPanel.add(passwordPanel); - - JPanel buttonPanel = new JPanel(); - buttonPanel.setLayout(new FlowLayout()); - buttonPanel.setAlignmentX(Component.CENTER_ALIGNMENT); - - JButton loginButton = new JButton("登录"); - loginButton.setBackground(new Color(76, 175, 80)); - loginButton.setForeground(Color.WHITE); - loginButton.setPreferredSize(new Dimension(120, 35)); - loginButton.setOpaque(true); - loginButton.setBorderPainted(false); - loginButton.setFocusPainted(false); - - JButton registerButton = new JButton("前往注册"); - registerButton.setBackground(new Color(33, 150, 243)); - registerButton.setForeground(Color.WHITE); - registerButton.setPreferredSize(new Dimension(120, 35)); - registerButton.setOpaque(true); - registerButton.setBorderPainted(false); - registerButton.setFocusPainted(false); - - buttonPanel.add(loginButton); - buttonPanel.add(Box.createHorizontalStrut(20)); - buttonPanel.add(registerButton); - - JLabel messageLabel = new JLabel(" "); - messageLabel.setAlignmentX(Component.CENTER_ALIGNMENT); - messageLabel.setForeground(Color.RED); - - mainPanel.add(Box.createVerticalStrut(20)); - mainPanel.add(titleLabel); - mainPanel.add(Box.createVerticalStrut(30)); - mainPanel.add(inputPanel); - mainPanel.add(Box.createVerticalStrut(30)); - mainPanel.add(buttonPanel); - mainPanel.add(Box.createVerticalStrut(20)); - mainPanel.add(messageLabel); - - // 初始化管理器 + private void initializeMVCComponents() { userManager = new UserManager(SYSTEM_EMAIL_HOST, SYSTEM_EMAIL_PORT, SYSTEM_EMAIL_USERNAME, SYSTEM_EMAIL_PASSWORD); quizController = new QuizController(); - loginButton.addActionListener(e -> { - String email = emailField.getText(); - String password = new String(passwordField.getPassword()); + viewData = new ViewData(); + appController = new AppController(); + viewBuilder = new ViewBuilder(); + eventHandlers = new EventHandlers(); + } + + // ==================== 重构后的界面方法 ==================== - if (userManager.login(email, password)) { - currentUser = userManager.getCurrentUser(); - messageLabel.setText("登录成功!"); - messageLabel.setForeground(Color.GREEN); + private void showLoginView() { + JPanel loginPanel = viewBuilder.buildLoginView((email, password) -> { + if (appController.handleLogin(email, password)) { showMainView(); } else { - messageLabel.setText("登录失败,请检查邮箱和密码!"); - messageLabel.setForeground(Color.RED); + // 错误处理可以在ViewBuilder中处理 + JOptionPane.showMessageDialog(mainFrame, "登录失败,请检查邮箱和密码!", "错误", JOptionPane.ERROR_MESSAGE); } - }); + }, () -> showRegisterView()); - registerButton.addActionListener(e -> showRegisterView()); + mainFrame.setContentPane(loginPanel); + mainFrame.revalidate(); + mainFrame.repaint(); + } + + private void showRegisterView() { + JPanel registerPanel = viewBuilder.buildRegisterView( + (username, email) -> appController.handleSendVerificationCode(username, email), + (username, email, code, password, confirmPassword) -> + appController.handleRegister(username, email, code, password, confirmPassword), + () -> showLoginView() + ); + + mainFrame.setContentPane(registerPanel); + mainFrame.revalidate(); + mainFrame.repaint(); + } + + private void showMainView() { + JPanel mainPanel = viewBuilder.buildMainView( + (difficulty) -> showQuestionCountView(difficulty), + () -> showChangePasswordView(), + () -> appController.handleLogout() + ); mainFrame.setContentPane(mainPanel); mainFrame.revalidate(); mainFrame.repaint(); } - // 注册界面 - 完全保持不变 - private void showRegisterView() { - JPanel mainPanel = new JPanel(); - mainPanel.setLayout(new BoxLayout(mainPanel, BoxLayout.Y_AXIS)); - mainPanel.setBorder(BorderFactory.createEmptyBorder(25, 25, 25, 25)); - - JLabel titleLabel = new JLabel("用户注册"); - titleLabel.setFont(new Font("微软雅黑", Font.BOLD, 20)); - titleLabel.setAlignmentX(Component.CENTER_ALIGNMENT); - - JPanel inputPanel = new JPanel(); - inputPanel.setLayout(new BoxLayout(inputPanel, BoxLayout.Y_AXIS)); - inputPanel.setAlignmentX(Component.CENTER_ALIGNMENT); - - JPanel usernamePanel = new JPanel(new FlowLayout(FlowLayout.LEFT)); - JLabel usernameLabel = new JLabel("用户名:"); - JTextField usernameField = new JTextField(20); - usernameField.setPreferredSize(new Dimension(200, 30)); - usernamePanel.add(usernameLabel); - usernamePanel.add(usernameField); - - JPanel emailPanel = new JPanel(new FlowLayout(FlowLayout.LEFT)); - JLabel emailLabel = new JLabel("邮箱:"); - JTextField emailField = new JTextField(20); - emailField.setPreferredSize(new Dimension(200, 30)); - emailPanel.add(emailLabel); - emailPanel.add(emailField); - - JPanel codePanel = new JPanel(new FlowLayout(FlowLayout.LEFT)); - JLabel codeLabel = new JLabel("验证码:"); - JTextField codeField = new JTextField(15); - codeField.setPreferredSize(new Dimension(120, 30)); - codeField.setEnabled(false); - - JButton sendCodeButton = new JButton("发送验证码"); - sendCodeButton.setBackground(new Color(255, 152, 0)); - sendCodeButton.setForeground(Color.WHITE); - sendCodeButton.setPreferredSize(new Dimension(120, 30)); - sendCodeButton.setOpaque(true); - sendCodeButton.setBorderPainted(false); - sendCodeButton.setFocusPainted(false); - - codePanel.add(codeLabel); - codePanel.add(codeField); - codePanel.add(Box.createHorizontalStrut(10)); - codePanel.add(sendCodeButton); - - JPanel passwordPanel = new JPanel(new FlowLayout(FlowLayout.LEFT)); - JLabel passwordLabel = new JLabel("密码:"); - JPasswordField passwordField = new JPasswordField(20); - passwordField.setPreferredSize(new Dimension(200, 30)); - passwordField.setEnabled(false); - passwordPanel.add(passwordLabel); - passwordPanel.add(passwordField); - - JPanel confirmPasswordPanel = new JPanel(new FlowLayout(FlowLayout.LEFT)); - JLabel confirmPasswordLabel = new JLabel("确认密码:"); - JPasswordField confirmPasswordField = new JPasswordField(20); - confirmPasswordField.setPreferredSize(new Dimension(200, 30)); - confirmPasswordField.setEnabled(false); - confirmPasswordPanel.add(confirmPasswordLabel); - confirmPasswordPanel.add(confirmPasswordField); - - inputPanel.add(usernamePanel); - inputPanel.add(Box.createVerticalStrut(15)); - inputPanel.add(emailPanel); - inputPanel.add(Box.createVerticalStrut(15)); - inputPanel.add(codePanel); - inputPanel.add(Box.createVerticalStrut(15)); - inputPanel.add(passwordPanel); - inputPanel.add(Box.createVerticalStrut(15)); - inputPanel.add(confirmPasswordPanel); - - JPanel buttonPanel = new JPanel(); - buttonPanel.setLayout(new FlowLayout()); - buttonPanel.setAlignmentX(Component.CENTER_ALIGNMENT); - - JButton registerButton = new JButton("注册"); - registerButton.setBackground(new Color(76, 175, 80)); - registerButton.setForeground(Color.WHITE); - registerButton.setPreferredSize(new Dimension(120, 35)); - registerButton.setEnabled(false); - registerButton.setOpaque(true); - registerButton.setBorderPainted(false); - registerButton.setFocusPainted(false); - - JButton backButton = new JButton("返回登录"); - backButton.setBackground(new Color(158, 158, 158)); - backButton.setForeground(Color.WHITE); - backButton.setPreferredSize(new Dimension(120, 35)); - backButton.setOpaque(true); - backButton.setBorderPainted(false); - backButton.setFocusPainted(false); - - buttonPanel.add(registerButton); - buttonPanel.add(Box.createHorizontalStrut(20)); - buttonPanel.add(backButton); - - JLabel messageLabel = new JLabel(" "); - messageLabel.setAlignmentX(Component.CENTER_ALIGNMENT); - messageLabel.setForeground(Color.RED); - - mainPanel.add(Box.createVerticalStrut(10)); - mainPanel.add(titleLabel); - mainPanel.add(Box.createVerticalStrut(25)); - mainPanel.add(inputPanel); - mainPanel.add(Box.createVerticalStrut(25)); - mainPanel.add(buttonPanel); - mainPanel.add(Box.createVerticalStrut(20)); - mainPanel.add(messageLabel); - - sendCodeButton.addActionListener(e -> { - String username = usernameField.getText().trim(); - String userEmail = emailField.getText().trim(); - - if (username.isEmpty()) { - messageLabel.setText("请输入用户名!"); - messageLabel.setForeground(Color.RED); - return; - } + private void showQuestionCountView(String difficulty) { + JPanel countPanel = viewBuilder.buildQuestionCountView(difficulty, + (count) -> { + if (appController.handleStartQuiz(difficulty, count)) { + showQuizView(); + } else { + JOptionPane.showMessageDialog(mainFrame, "题目数量必须在10-30之间!", "错误", JOptionPane.ERROR_MESSAGE); + } + }, + () -> showMainView() + ); - if (userEmail.isEmpty()) { - messageLabel.setText("请输入邮箱地址!"); - messageLabel.setForeground(Color.RED); - return; - } + mainFrame.setContentPane(countPanel); + mainFrame.revalidate(); + mainFrame.repaint(); + } - if (!isValidEmail(userEmail)) { - messageLabel.setText("邮箱格式错误!请输入有效的邮箱地址。"); - messageLabel.setForeground(Color.RED); - return; - } + private void showQuizView() { + QuizController.Question currentQuestion = quizController.getCurrentQuestion(); + if (currentQuestion == null) { + showScoreView(); + return; + } - if (userManager.isUsernameExists(username)) { - messageLabel.setText("用户名已存在,请选择其他用户名!"); - messageLabel.setForeground(Color.RED); - return; - } + JPanel quizPanel = viewBuilder.buildQuizView( + quizController.getCurrentQuestionNumber(), + quizController.getTotalQuestions(), + currentQuestion, + (selectedAnswer) -> { + appController.handleAnswerSubmit(selectedAnswer); + if (quizController.hasNextQuestion()) { + quizController.nextQuestion(); + showQuizView(); // 刷新界面显示下一题 + } else { + showScoreView(); + } + } + ); - if (userManager.isUserExists(userEmail)) { - messageLabel.setText("该邮箱已被注册,请使用其他邮箱!"); - messageLabel.setForeground(Color.RED); - return; - } + mainFrame.setContentPane(quizPanel); + mainFrame.revalidate(); + mainFrame.repaint(); + mainFrame.setSize(550, 500); + mainFrame.setLocationRelativeTo(null); + } + + private void showScoreView() { + int score = quizController.getScore(); + int total = quizController.getTotalQuestions(); + double percentage = quizController.getPercentage(); - sendCodeButton.setEnabled(false); - sendCodeButton.setText("发送中..."); + JPanel scorePanel = viewBuilder.buildScoreView(score, total, percentage, + () -> showMainView() + ); - new Thread(() -> { - String code = userManager.generateAndSendVerificationCode(userEmail); + mainFrame.setContentPane(scorePanel); + mainFrame.revalidate(); + mainFrame.repaint(); + } - SwingUtilities.invokeLater(() -> { - if (code != null) { - messageLabel.setText("验证码已发送到您的邮箱: " + userEmail + "
请查看邮件并输入验证码"); - messageLabel.setForeground(Color.GREEN); + private void showChangePasswordView() { + JPanel changePasswordPanel = viewBuilder.buildChangePasswordView( + (oldPassword, newPassword, confirmPassword) -> + appController.handleChangePassword(oldPassword, newPassword, confirmPassword), + () -> showMainView() + ); - codeField.setEnabled(true); - passwordField.setEnabled(true); - confirmPasswordField.setEnabled(true); - registerButton.setEnabled(true); - } else { - messageLabel.setText("验证码发送失败,请检查邮箱地址或稍后重试!"); - messageLabel.setForeground(Color.RED); - sendCodeButton.setEnabled(true); - sendCodeButton.setText("发送验证码"); - } - }); - }).start(); - }); + mainFrame.setContentPane(changePasswordPanel); + mainFrame.revalidate(); + mainFrame.repaint(); + } + + private boolean isValidEmail(String email) { + String emailRegex = "^[a-zA-Z0-9_+&*-]+(?:\\.[a-zA-Z0-9_+&*-]+)*@(?:[a-zA-Z0-9-]+\\.)+[a-zA-Z]{2,7}$"; + return email != null && email.matches(emailRegex); + } + + // ========================================================================= + // MVC 架构内部类 + // ========================================================================= + + /** + * 数据模型 - 负责管理视图数据 + */ + private class ViewData { + private UserManager.User currentUser; + private String currentMessage; + private Color messageColor; + + public UserManager.User getCurrentUser() { + return currentUser; + } + + public void setCurrentUser(UserManager.User user) { + this.currentUser = user; + } + + public String getCurrentMessage() { + return currentMessage; + } + + public void setCurrentMessage(String message, Color color) { + this.currentMessage = message; + this.messageColor = color; + } - registerButton.addActionListener(e -> { - String username = usernameField.getText().trim(); - String email = emailField.getText().trim(); - String code = codeField.getText().trim(); - String password = new String(passwordField.getPassword()); - String confirmPassword = new String(confirmPasswordField.getPassword()); - - if (username.isEmpty()) { - messageLabel.setText("请输入用户名!"); - messageLabel.setForeground(Color.RED); - return; + public Color getMessageColor() { + return messageColor; + } + } + + /** + * 应用控制器 - 处理所有业务逻辑 + */ + private class AppController { + public boolean handleLogin(String email, String password) { + if (userManager.login(email, password)) { + viewData.setCurrentUser(userManager.getCurrentUser()); + return true; } + return false; + } - if (email.isEmpty()) { - messageLabel.setText("请输入邮箱地址!"); - messageLabel.setForeground(Color.RED); - return; + public boolean handleSendVerificationCode(String username, String email) { + if (username.isEmpty() || email.isEmpty()) { + return false; } - if (code.isEmpty()) { - messageLabel.setText("请输入验证码!"); - messageLabel.setForeground(Color.RED); - return; + if (userManager.isUsernameExists(username)) { + return false; } - if (password.isEmpty()) { - messageLabel.setText("请输入密码!"); - messageLabel.setForeground(Color.RED); - return; + if (userManager.isUserExists(email)) { + return false; } + String code = userManager.generateAndSendVerificationCode(email); + return code != null; + } + + public boolean handleRegister(String username, String email, String code, + String password, String confirmPassword) { if (!password.equals(confirmPassword)) { - messageLabel.setText("两次输入的密码不一致!"); - messageLabel.setForeground(Color.RED); - return; + return false; } if (!userManager.isValidPassword(password)) { - messageLabel.setText("密码不符合要求:
- 长度必须在6-10位之间
- 必须包含大写字母、小写字母和数字"); - messageLabel.setForeground(Color.RED); - return; + return false; } - if (userManager.registerUser(username, email, code, password)) { - messageLabel.setText("注册成功!请返回登录"); - messageLabel.setForeground(Color.GREEN); - registerButton.setEnabled(false); - sendCodeButton.setEnabled(false); - } else { - messageLabel.setText("注册失败!请检查:
- 验证码是否正确
- 密码是否符合要求
- 邮箱或用户名是否已注册"); - messageLabel.setForeground(Color.RED); + return userManager.registerUser(username, email, code, password); + } + + public boolean handleStartQuiz(String difficulty, int count) { + if (count >= 10 && count <= 30) { + quizController.startNewQuiz(difficulty, count); + return true; } - }); + return false; + } - backButton.addActionListener(e -> showLoginView()); + public void handleAnswerSubmit(int selectedAnswer) { + quizController.submitAnswer(selectedAnswer); + } - mainFrame.setContentPane(mainPanel); - mainFrame.revalidate(); - mainFrame.repaint(); - } + public boolean handleChangePassword(String oldPassword, String newPassword, String confirmPassword) { + if (!newPassword.equals(confirmPassword)) { + return false; + } - // 主界面 - 完全保持不变 - private void showMainView() { - JPanel mainPanel = new JPanel(); - mainPanel.setLayout(new BoxLayout(mainPanel, BoxLayout.Y_AXIS)); - mainPanel.setBorder(BorderFactory.createEmptyBorder(40, 40, 40, 40)); - - String welcomeText = currentUser != null ? - "欢迎 " + currentUser.getUsername() + " 使用数学学习软件!" : - "欢迎使用数学学习软件!"; - - JLabel welcomeLabel = new JLabel(welcomeText); - welcomeLabel.setFont(new Font("微软雅黑", Font.BOLD, 22)); - welcomeLabel.setAlignmentX(Component.CENTER_ALIGNMENT); - - JLabel instructionLabel = new JLabel("请选择题目难度:"); - instructionLabel.setFont(new Font("微软雅黑", Font.PLAIN, 16)); - instructionLabel.setAlignmentX(Component.CENTER_ALIGNMENT); - - JPanel buttonPanel = new JPanel(); - buttonPanel.setLayout(new BoxLayout(buttonPanel, BoxLayout.Y_AXIS)); - buttonPanel.setAlignmentX(Component.CENTER_ALIGNMENT); - - JButton primaryBtn = createDifficultyButton("小学", new Color(76, 175, 80)); - JButton middleBtn = createDifficultyButton("初中", new Color(33, 150, 243)); - JButton highBtn = createDifficultyButton("高中", new Color(255, 152, 0)); - - buttonPanel.add(primaryBtn); - buttonPanel.add(Box.createVerticalStrut(15)); - buttonPanel.add(middleBtn); - buttonPanel.add(Box.createVerticalStrut(15)); - buttonPanel.add(highBtn); - - JPanel functionPanel = new JPanel(); - functionPanel.setLayout(new FlowLayout()); - functionPanel.setAlignmentX(Component.CENTER_ALIGNMENT); - - JButton changePasswordBtn = new JButton("修改密码"); - changePasswordBtn.setBackground(new Color(96, 125, 139)); - changePasswordBtn.setForeground(Color.WHITE); - changePasswordBtn.setPreferredSize(new Dimension(120, 35)); - changePasswordBtn.setOpaque(true); - changePasswordBtn.setBorderPainted(false); - changePasswordBtn.setFocusPainted(false); - - JButton logoutBtn = new JButton("退出登录"); - logoutBtn.setBackground(new Color(244, 67, 54)); - logoutBtn.setForeground(Color.WHITE); - logoutBtn.setPreferredSize(new Dimension(120, 35)); - logoutBtn.setOpaque(true); - logoutBtn.setBorderPainted(false); - logoutBtn.setFocusPainted(false); - - functionPanel.add(changePasswordBtn); - functionPanel.add(Box.createHorizontalStrut(20)); - functionPanel.add(logoutBtn); - - mainPanel.add(Box.createVerticalStrut(20)); - mainPanel.add(welcomeLabel); - mainPanel.add(Box.createVerticalStrut(10)); - mainPanel.add(instructionLabel); - mainPanel.add(Box.createVerticalStrut(30)); - mainPanel.add(buttonPanel); - mainPanel.add(Box.createVerticalStrut(30)); - mainPanel.add(functionPanel); - - changePasswordBtn.addActionListener(e -> showChangePasswordView()); - logoutBtn.addActionListener(e -> { + if (!userManager.isValidPassword(newPassword)) { + return false; + } + + return userManager.changePassword(oldPassword, newPassword); + } + + public void handleLogout() { userManager.logout(); - currentUser = null; + viewData.setCurrentUser(null); showLoginView(); - }); - - mainFrame.setContentPane(mainPanel); - mainFrame.revalidate(); - mainFrame.repaint(); + } } - private JButton createDifficultyButton(String text, Color color) { - JButton button = new JButton(text); - button.setBackground(color); - button.setForeground(Color.WHITE); - button.setFont(new Font("微软雅黑", Font.BOLD, 16)); - button.setPreferredSize(new Dimension(140, 45)); - button.setMaximumSize(new Dimension(140, 45)); - button.setAlignmentX(Component.CENTER_ALIGNMENT); - button.setOpaque(true); - button.setBorderPainted(false); - button.setFocusPainted(false); - - button.addActionListener(e -> showQuestionCountView(text)); - return button; - } + /** + * 视图构建器 - 负责构建所有界面组件 + */ + private class ViewBuilder { + public JPanel buildLoginView(LoginListener loginListener, Runnable backToLogin) { + JPanel panel = new JPanel(); + panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS)); + panel.setBorder(BorderFactory.createEmptyBorder(30, 30, 30, 30)); + + // 标题 + JLabel titleLabel = new JLabel("数学学习软件 - 登录"); + titleLabel.setFont(new Font("微软雅黑", Font.BOLD, 20)); + titleLabel.setAlignmentX(Component.CENTER_ALIGNMENT); + + // 输入面板 + JPanel inputPanel = new JPanel(); + inputPanel.setLayout(new BoxLayout(inputPanel, BoxLayout.Y_AXIS)); + inputPanel.setAlignmentX(Component.CENTER_ALIGNMENT); + + JTextField emailField = new JTextField(20); + emailField.setPreferredSize(new Dimension(200, 30)); + + JPasswordField passwordField = new JPasswordField(20); + passwordField.setPreferredSize(new Dimension(200, 30)); + + JPanel emailPanel = createLabelFieldPanel("邮箱:", emailField); + JPanel passwordPanel = createLabelFieldPanel("密码:", passwordField); + + inputPanel.add(emailPanel); + inputPanel.add(Box.createVerticalStrut(15)); + inputPanel.add(passwordPanel); + + // 按钮面板 + JPanel buttonPanel = new JPanel(); + buttonPanel.setLayout(new FlowLayout()); + buttonPanel.setAlignmentX(Component.CENTER_ALIGNMENT); + + JButton loginButton = createStyledButton("登录", new Color(76, 175, 80), 120, 35); + JButton registerButton = createStyledButton("前往注册", new Color(33, 150, 243), 120, 35); + + loginButton.addActionListener(e -> { + String email = emailField.getText(); + String password = new String(passwordField.getPassword()); + loginListener.onLogin(email, password); + }); + + registerButton.addActionListener(e -> backToLogin.run()); + + buttonPanel.add(loginButton); + buttonPanel.add(Box.createHorizontalStrut(20)); + buttonPanel.add(registerButton); + + // 组装主面板 + panel.add(Box.createVerticalStrut(20)); + panel.add(titleLabel); + panel.add(Box.createVerticalStrut(30)); + panel.add(inputPanel); + panel.add(Box.createVerticalStrut(30)); + panel.add(buttonPanel); + + return panel; + } - // 输入题目数量界面 - 完全保持不变 - private void showQuestionCountView(String difficulty) { - JPanel mainPanel = new JPanel(); - mainPanel.setLayout(new BoxLayout(mainPanel, BoxLayout.Y_AXIS)); - mainPanel.setBorder(BorderFactory.createEmptyBorder(40, 40, 40, 40)); - - JLabel titleLabel = new JLabel("准备生成" + difficulty + "数学题目"); - titleLabel.setFont(new Font("微软雅黑", Font.BOLD, 20)); - titleLabel.setAlignmentX(Component.CENTER_ALIGNMENT); - - JLabel instructionLabel = new JLabel("请输入题目数量 (10-30):"); - instructionLabel.setFont(new Font("微软雅黑", Font.PLAIN, 14)); - instructionLabel.setAlignmentX(Component.CENTER_ALIGNMENT); - - JPanel inputPanel = new JPanel(); - inputPanel.setLayout(new FlowLayout()); - inputPanel.setAlignmentX(Component.CENTER_ALIGNMENT); - - JTextField countField = new JTextField(10); - countField.setPreferredSize(new Dimension(100, 30)); - inputPanel.add(countField); - - JPanel buttonPanel = new JPanel(); - buttonPanel.setLayout(new FlowLayout()); - buttonPanel.setAlignmentX(Component.CENTER_ALIGNMENT); - - JButton startButton = new JButton("开始答题"); - startButton.setBackground(new Color(76, 175, 80)); - startButton.setForeground(Color.WHITE); - startButton.setPreferredSize(new Dimension(120, 35)); - startButton.setOpaque(true); - startButton.setBorderPainted(false); - startButton.setFocusPainted(false); - - JButton backButton = new JButton("返回"); - backButton.setBackground(new Color(158, 158, 158)); - backButton.setForeground(Color.WHITE); - backButton.setPreferredSize(new Dimension(120, 35)); - backButton.setOpaque(true); - backButton.setBorderPainted(false); - backButton.setFocusPainted(false); - - buttonPanel.add(startButton); - buttonPanel.add(Box.createHorizontalStrut(20)); - buttonPanel.add(backButton); - - JLabel messageLabel = new JLabel(" "); - messageLabel.setAlignmentX(Component.CENTER_ALIGNMENT); - messageLabel.setForeground(Color.RED); - - mainPanel.add(Box.createVerticalStrut(20)); - mainPanel.add(titleLabel); - mainPanel.add(Box.createVerticalStrut(20)); - mainPanel.add(instructionLabel); - mainPanel.add(Box.createVerticalStrut(15)); - mainPanel.add(inputPanel); - mainPanel.add(Box.createVerticalStrut(25)); - mainPanel.add(buttonPanel); - mainPanel.add(Box.createVerticalStrut(20)); - mainPanel.add(messageLabel); - - startButton.addActionListener(e -> { - try { - int count = Integer.parseInt(countField.getText()); - if (count >= 10 && count <= 30) { - messageLabel.setText("正在生成题目,请稍候..."); - messageLabel.setForeground(Color.BLUE); - mainFrame.revalidate(); - mainFrame.repaint(); - - SwingWorker worker = new SwingWorker() { - @Override - protected Void doInBackground() throws Exception { - quizController.startNewQuiz(difficulty, count); - return null; - } + public JPanel buildRegisterView(SendCodeListener sendCodeListener, RegisterListener registerListener, Runnable backAction) { + JPanel panel = new JPanel(); + panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS)); + panel.setBorder(BorderFactory.createEmptyBorder(25, 25, 25, 25)); + + JLabel titleLabel = new JLabel("用户注册"); + titleLabel.setFont(new Font("微软雅黑", Font.BOLD, 20)); + titleLabel.setAlignmentX(Component.CENTER_ALIGNMENT); + + JPanel inputPanel = new JPanel(); + inputPanel.setLayout(new BoxLayout(inputPanel, BoxLayout.Y_AXIS)); + inputPanel.setAlignmentX(Component.CENTER_ALIGNMENT); + + JTextField usernameField = new JTextField(20); + JTextField emailField = new JTextField(20); + JTextField codeField = new JTextField(15); + JPasswordField passwordField = new JPasswordField(20); + JPasswordField confirmPasswordField = new JPasswordField(20); + + // 初始禁用状态 + codeField.setEnabled(false); + passwordField.setEnabled(false); + confirmPasswordField.setEnabled(false); + + JButton sendCodeButton = createStyledButton("发送验证码", new Color(255, 152, 0), 120, 30); + JButton registerButton = createStyledButton("注册", new Color(76, 175, 80), 120, 35); + registerButton.setEnabled(false); // 初始禁用注册按钮 + JButton backButton = createStyledButton("返回登录", new Color(158, 158, 158), 120, 35); + + // 添加消息标签 + JLabel messageLabel = new JLabel(" "); + messageLabel.setAlignmentX(Component.CENTER_ALIGNMENT); + messageLabel.setForeground(Color.RED); + + // 构建各个输入行 + JPanel usernamePanel = createLabelFieldPanel("用户名:", usernameField); + JPanel emailPanel = createLabelFieldPanel("邮箱:", emailField); + + JPanel codePanel = new JPanel(new FlowLayout(FlowLayout.LEFT)); + codePanel.add(new JLabel("验证码:")); + codePanel.add(codeField); + codePanel.add(Box.createHorizontalStrut(10)); + codePanel.add(sendCodeButton); + + JPanel passwordPanel = createLabelFieldPanel("密码:", passwordField); + JPanel confirmPasswordPanel = createLabelFieldPanel("确认密码:", confirmPasswordField); + + inputPanel.add(usernamePanel); + inputPanel.add(Box.createVerticalStrut(15)); + inputPanel.add(emailPanel); + inputPanel.add(Box.createVerticalStrut(15)); + inputPanel.add(codePanel); + inputPanel.add(Box.createVerticalStrut(15)); + inputPanel.add(passwordPanel); + inputPanel.add(Box.createVerticalStrut(15)); + inputPanel.add(confirmPasswordPanel); + + // 按钮面板 + JPanel buttonPanel = new JPanel(); + buttonPanel.setLayout(new FlowLayout()); + buttonPanel.setAlignmentX(Component.CENTER_ALIGNMENT); + + buttonPanel.add(registerButton); + buttonPanel.add(Box.createHorizontalStrut(20)); + buttonPanel.add(backButton); + + // 发送验证码事件处理 + sendCodeButton.addActionListener(e -> { + String username = usernameField.getText().trim(); + String email = emailField.getText().trim(); + + // 客户端验证 + if (username.isEmpty()) { + messageLabel.setText("请输入用户名!"); + messageLabel.setForeground(Color.RED); + return; + } + + if (email.isEmpty()) { + messageLabel.setText("请输入邮箱地址!"); + messageLabel.setForeground(Color.RED); + return; + } + + if (!isValidEmail(email)) { + messageLabel.setText("邮箱格式错误!请输入有效的邮箱地址。"); + messageLabel.setForeground(Color.RED); + return; + } - @Override - protected void done() { - showQuizView(); + // 检查用户名是否已存在 + if (userManager.isUsernameExists(username)) { + messageLabel.setText("用户名已存在,请选择其他用户名!"); + messageLabel.setForeground(Color.RED); + return; + } + + // 检查邮箱是否已被注册 + if (userManager.isUserExists(email)) { + messageLabel.setText("该邮箱已被注册,请使用其他邮箱!"); + messageLabel.setForeground(Color.RED); + return; + } + + // 禁用发送按钮,显示发送中状态 + sendCodeButton.setEnabled(false); + sendCodeButton.setText("发送中..."); + messageLabel.setText("正在发送验证码,请稍候..."); + messageLabel.setForeground(Color.BLUE); + + // 在新线程中发送验证码,避免阻塞UI + new Thread(() -> { + boolean success = sendCodeListener.onSendCode(username, email); + + SwingUtilities.invokeLater(() -> { + if (success) { + messageLabel.setText("验证码已发送到您的邮箱: " + email + "
请查看邮件并输入验证码"); + messageLabel.setForeground(Color.GREEN); + + // 启用相关输入框 + codeField.setEnabled(true); + passwordField.setEnabled(true); + confirmPasswordField.setEnabled(true); + registerButton.setEnabled(true); + } else { + messageLabel.setText("验证码发送失败,请检查邮箱地址或稍后重试!"); + messageLabel.setForeground(Color.RED); } - }; - worker.execute(); + + // 恢复发送按钮状态 + sendCodeButton.setEnabled(true); + sendCodeButton.setText("发送验证码"); + }); + }).start(); + }); + + // 注册事件处理 + registerButton.addActionListener(e -> { + String username = usernameField.getText().trim(); + String email = emailField.getText().trim(); + String code = codeField.getText().trim(); + String password = new String(passwordField.getPassword()); + String confirmPassword = new String(confirmPasswordField.getPassword()); + + // 客户端验证 + if (username.isEmpty()) { + messageLabel.setText("请输入用户名!"); + messageLabel.setForeground(Color.RED); + return; + } + + if (email.isEmpty()) { + messageLabel.setText("请输入邮箱地址!"); + messageLabel.setForeground(Color.RED); + return; + } + + if (code.isEmpty()) { + messageLabel.setText("请输入验证码!"); + messageLabel.setForeground(Color.RED); + return; + } + + if (password.isEmpty()) { + messageLabel.setText("请输入密码!"); + messageLabel.setForeground(Color.RED); + return; + } + + if (!password.equals(confirmPassword)) { + messageLabel.setText("两次输入的密码不一致!"); + messageLabel.setForeground(Color.RED); + return; + } + + if (!userManager.isValidPassword(password)) { + messageLabel.setText("密码不符合要求:
- 长度必须在6-10位之间
- 必须包含大写字母、小写字母和数字"); + messageLabel.setForeground(Color.RED); + return; + } + + // 调用注册逻辑 + boolean success = registerListener.onRegister(username, email, code, password, confirmPassword); + + if (success) { + messageLabel.setText("注册成功!请返回登录"); + messageLabel.setForeground(Color.GREEN); + registerButton.setEnabled(false); + sendCodeButton.setEnabled(false); } else { - messageLabel.setText("题目数量必须在10-30之间!"); + messageLabel.setText("注册失败!请检查:
- 验证码是否正确
- 密码是否符合要求
- 邮箱或用户名是否已注册"); messageLabel.setForeground(Color.RED); } - } catch (NumberFormatException ex) { - messageLabel.setText("请输入有效的数字!"); - messageLabel.setForeground(Color.RED); - } - }); + }); - backButton.addActionListener(e -> showMainView()); + backButton.addActionListener(e -> backAction.run()); - mainFrame.setContentPane(mainPanel); - mainFrame.revalidate(); - mainFrame.repaint(); - } + // 组装主面板 + panel.add(Box.createVerticalStrut(10)); + panel.add(titleLabel); + panel.add(Box.createVerticalStrut(25)); + panel.add(inputPanel); + panel.add(Box.createVerticalStrut(15)); + panel.add(messageLabel); // 添加消息标签 + panel.add(Box.createVerticalStrut(10)); + panel.add(buttonPanel); - // 答题界面 - 完全保持不变 - private void showQuizView() { - JPanel mainPanel = new JPanel(); - mainPanel.setLayout(new BorderLayout()); - mainPanel.setBorder(BorderFactory.createEmptyBorder(15, 15, 15, 15)); + return panel; + } - QuizController.Question currentQuestion = quizController.getCurrentQuestion(); - if (currentQuestion == null) { - showScoreView(); - return; + public JPanel buildMainView(DifficultySelectListener difficultyListener, + Runnable changePasswordAction, Runnable logoutAction) { + JPanel panel = new JPanel(); + panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS)); + panel.setBorder(BorderFactory.createEmptyBorder(40, 40, 40, 40)); + + String welcomeText = viewData.getCurrentUser() != null ? + "欢迎 " + viewData.getCurrentUser().getUsername() + " 使用数学学习软件!" : + "欢迎使用数学学习软件!"; + + JLabel welcomeLabel = new JLabel(welcomeText); + welcomeLabel.setFont(new Font("微软雅黑", Font.BOLD, 22)); + welcomeLabel.setAlignmentX(Component.CENTER_ALIGNMENT); + + JLabel instructionLabel = new JLabel("请选择题目难度:"); + instructionLabel.setFont(new Font("微软雅黑", Font.PLAIN, 16)); + instructionLabel.setAlignmentX(Component.CENTER_ALIGNMENT); + + // 难度按钮面板 + JPanel buttonPanel = new JPanel(); + buttonPanel.setLayout(new BoxLayout(buttonPanel, BoxLayout.Y_AXIS)); + buttonPanel.setAlignmentX(Component.CENTER_ALIGNMENT); + + JButton primaryBtn = createDifficultyButton("小学", new Color(76, 175, 80)); + JButton middleBtn = createDifficultyButton("初中", new Color(33, 150, 243)); + JButton highBtn = createDifficultyButton("高中", new Color(255, 152, 0)); + + primaryBtn.addActionListener(e -> difficultyListener.onDifficultySelected("小学")); + middleBtn.addActionListener(e -> difficultyListener.onDifficultySelected("初中")); + highBtn.addActionListener(e -> difficultyListener.onDifficultySelected("高中")); + + buttonPanel.add(primaryBtn); + buttonPanel.add(Box.createVerticalStrut(15)); + buttonPanel.add(middleBtn); + buttonPanel.add(Box.createVerticalStrut(15)); + buttonPanel.add(highBtn); + + // 功能按钮面板 + JPanel functionPanel = new JPanel(); + functionPanel.setLayout(new FlowLayout()); + functionPanel.setAlignmentX(Component.CENTER_ALIGNMENT); + + JButton changePasswordBtn = createStyledButton("修改密码", new Color(96, 125, 139), 120, 35); + JButton logoutBtn = createStyledButton("退出登录", new Color(244, 67, 54), 120, 35); + + changePasswordBtn.addActionListener(e -> changePasswordAction.run()); + logoutBtn.addActionListener(e -> logoutAction.run()); + + functionPanel.add(changePasswordBtn); + functionPanel.add(Box.createHorizontalStrut(20)); + functionPanel.add(logoutBtn); + + // 组装主面板 + panel.add(Box.createVerticalStrut(20)); + panel.add(welcomeLabel); + panel.add(Box.createVerticalStrut(10)); + panel.add(instructionLabel); + panel.add(Box.createVerticalStrut(30)); + panel.add(buttonPanel); + panel.add(Box.createVerticalStrut(30)); + panel.add(functionPanel); + + return panel; } - JPanel infoPanel = new JPanel(); - infoPanel.setLayout(new BoxLayout(infoPanel, BoxLayout.Y_AXIS)); - infoPanel.setBorder(BorderFactory.createEmptyBorder(10, 10, 20, 10)); + public JPanel buildQuestionCountView(String difficulty, CountSubmitListener countListener, Runnable backAction) { + JPanel panel = new JPanel(); + panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS)); + panel.setBorder(BorderFactory.createEmptyBorder(40, 40, 40, 40)); + + JLabel titleLabel = new JLabel("准备生成" + difficulty + "数学题目"); + titleLabel.setFont(new Font("微软雅黑", Font.BOLD, 20)); + titleLabel.setAlignmentX(Component.CENTER_ALIGNMENT); + + JLabel instructionLabel = new JLabel("请输入题目数量 (10-30):"); + instructionLabel.setFont(new Font("微软雅黑", Font.PLAIN, 14)); + instructionLabel.setAlignmentX(Component.CENTER_ALIGNMENT); + + JPanel inputPanel = new JPanel(); + inputPanel.setLayout(new FlowLayout()); + inputPanel.setAlignmentX(Component.CENTER_ALIGNMENT); + + JTextField countField = new JTextField(10); + countField.setPreferredSize(new Dimension(100, 30)); + inputPanel.add(countField); + + JPanel buttonPanel = new JPanel(); + buttonPanel.setLayout(new FlowLayout()); + buttonPanel.setAlignmentX(Component.CENTER_ALIGNMENT); - JLabel questionNumberLabel = new JLabel(); - questionNumberLabel.setFont(new Font("微软雅黑", Font.BOLD, 16)); + JButton startButton = createStyledButton("开始答题", new Color(76, 175, 80), 120, 35); + JButton backButton = createStyledButton("返回", new Color(158, 158, 158), 120, 35); - JLabel questionContentLabel = new JLabel(); - questionContentLabel.setFont(new Font("微软雅黑", Font.PLAIN, 16)); - questionContentLabel.setBorder(BorderFactory.createEmptyBorder(10, 0, 10, 0)); + startButton.addActionListener(e -> { + try { + int count = Integer.parseInt(countField.getText()); + countListener.onCountSubmit(count); + } catch (NumberFormatException ex) { + JOptionPane.showMessageDialog(mainFrame, "请输入有效的数字!", "错误", JOptionPane.ERROR_MESSAGE); + } + }); - infoPanel.add(questionNumberLabel); - infoPanel.add(Box.createVerticalStrut(15)); - infoPanel.add(questionContentLabel); + backButton.addActionListener(e -> backAction.run()); - JPanel optionsPanel = new JPanel(); - optionsPanel.setLayout(new BoxLayout(optionsPanel, BoxLayout.Y_AXIS)); - optionsPanel.setBorder(BorderFactory.createEmptyBorder(10, 20, 10, 20)); + buttonPanel.add(startButton); + buttonPanel.add(Box.createHorizontalStrut(20)); + buttonPanel.add(backButton); - ButtonGroup answerGroup = new ButtonGroup(); - JRadioButton[] optionButtons = new JRadioButton[4]; + panel.add(Box.createVerticalStrut(20)); + panel.add(titleLabel); + panel.add(Box.createVerticalStrut(20)); + panel.add(instructionLabel); + panel.add(Box.createVerticalStrut(15)); + panel.add(inputPanel); + panel.add(Box.createVerticalStrut(25)); + panel.add(buttonPanel); - for (int i = 0; i < 4; i++) { - optionButtons[i] = new JRadioButton(); - optionButtons[i].setFont(new Font("微软雅黑", Font.PLAIN, 14)); - optionButtons[i].setActionCommand(String.valueOf(i)); - answerGroup.add(optionButtons[i]); - optionsPanel.add(optionButtons[i]); - optionsPanel.add(Box.createVerticalStrut(12)); + return panel; } - JPanel buttonPanel = new JPanel(); - buttonPanel.setLayout(new FlowLayout()); - buttonPanel.setBorder(BorderFactory.createEmptyBorder(20, 10, 10, 10)); - - JButton submitButton = new JButton("提交答案"); - submitButton.setBackground(new Color(76, 175, 80)); - submitButton.setForeground(Color.WHITE); - submitButton.setPreferredSize(new Dimension(140, 40)); - submitButton.setFont(new Font("微软雅黑", Font.BOLD, 14)); - submitButton.setOpaque(true); - submitButton.setBorderPainted(false); - submitButton.setFocusPainted(false); - - buttonPanel.add(submitButton); - - JLabel messageLabel = new JLabel(" "); - messageLabel.setForeground(Color.RED); - messageLabel.setHorizontalAlignment(SwingConstants.CENTER); - messageLabel.setBorder(BorderFactory.createEmptyBorder(10, 5, 5, 5)); - - updateQuestionDisplay(questionNumberLabel, questionContentLabel, optionButtons); - - submitButton.addActionListener(e -> { - ButtonModel selectedModel = answerGroup.getSelection(); - if (selectedModel == null) { - messageLabel.setText("请选择一个答案!"); - messageLabel.setForeground(Color.RED); - return; - } + public JPanel buildQuizView(int currentNumber, int totalQuestions, QuizController.Question question, AnswerSubmitListener answerListener) { + JPanel panel = new JPanel(); + panel.setLayout(new BorderLayout()); + panel.setBorder(BorderFactory.createEmptyBorder(15, 15, 15, 15)); - int selectedIndex = Integer.parseInt(selectedModel.getActionCommand()); - quizController.submitAnswer(selectedIndex); - answerGroup.clearSelection(); - messageLabel.setText(""); + // 信息面板 + JPanel infoPanel = new JPanel(); + infoPanel.setLayout(new BoxLayout(infoPanel, BoxLayout.Y_AXIS)); + infoPanel.setBorder(BorderFactory.createEmptyBorder(10, 10, 20, 10)); - if (quizController.hasNextQuestion()) { - quizController.nextQuestion(); - updateQuestionDisplay(questionNumberLabel, questionContentLabel, optionButtons); - } else { - showScoreView(); + JLabel questionNumberLabel = new JLabel("第 " + currentNumber + " 题 / 共 " + totalQuestions + " 题"); + questionNumberLabel.setFont(new Font("微软雅黑", Font.BOLD, 16)); + + JLabel questionContentLabel = new JLabel("" + question.getContent() + ""); + questionContentLabel.setFont(new Font("微软雅黑", Font.PLAIN, 16)); + questionContentLabel.setBorder(BorderFactory.createEmptyBorder(10, 0, 10, 0)); + + infoPanel.add(questionNumberLabel); + infoPanel.add(Box.createVerticalStrut(15)); + infoPanel.add(questionContentLabel); + + // 选项面板 + JPanel optionsPanel = new JPanel(); + optionsPanel.setLayout(new BoxLayout(optionsPanel, BoxLayout.Y_AXIS)); + optionsPanel.setBorder(BorderFactory.createEmptyBorder(10, 20, 10, 20)); + + ButtonGroup answerGroup = new ButtonGroup(); + JRadioButton[] optionButtons = new JRadioButton[4]; + + for (int i = 0; i < 4; i++) { + optionButtons[i] = new JRadioButton((char) ('A' + i) + ". " + question.getOptions()[i]); + optionButtons[i].setFont(new Font("微软雅黑", Font.PLAIN, 14)); + optionButtons[i].setActionCommand(String.valueOf(i)); + answerGroup.add(optionButtons[i]); + optionsPanel.add(optionButtons[i]); + optionsPanel.add(Box.createVerticalStrut(12)); } - }); - JScrollPane scrollPane = new JScrollPane(optionsPanel); - scrollPane.setBorder(BorderFactory.createEmptyBorder()); - scrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED); - scrollPane.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_NEVER); + // 提交按钮 + JPanel buttonPanel = new JPanel(); + buttonPanel.setLayout(new FlowLayout()); + buttonPanel.setBorder(BorderFactory.createEmptyBorder(20, 10, 10, 10)); - mainPanel.add(infoPanel, BorderLayout.NORTH); - mainPanel.add(scrollPane, BorderLayout.CENTER); + JButton submitButton = createStyledButton("提交答案", new Color(76, 175, 80), 140, 40); + submitButton.setFont(new Font("微软雅黑", Font.BOLD, 14)); - JPanel bottomPanel = new JPanel(new BorderLayout()); - bottomPanel.add(buttonPanel, BorderLayout.NORTH); - bottomPanel.add(messageLabel, BorderLayout.SOUTH); + submitButton.addActionListener(e -> { + ButtonModel selectedModel = answerGroup.getSelection(); + if (selectedModel == null) { + JOptionPane.showMessageDialog(mainFrame, "请选择一个答案!", "提示", JOptionPane.WARNING_MESSAGE); + return; + } + int selectedIndex = Integer.parseInt(selectedModel.getActionCommand()); + answerListener.onAnswerSubmit(selectedIndex); + }); - mainPanel.add(bottomPanel, BorderLayout.SOUTH); + buttonPanel.add(submitButton); - mainFrame.setContentPane(mainPanel); - mainFrame.revalidate(); - mainFrame.repaint(); - mainFrame.setSize(550, 500); - mainFrame.setLocationRelativeTo(null); - } + JScrollPane scrollPane = new JScrollPane(optionsPanel); + scrollPane.setBorder(BorderFactory.createEmptyBorder()); + scrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED); + scrollPane.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_NEVER); - private void updateQuestionDisplay(JLabel numberLabel, JLabel contentLabel, JRadioButton[] optionButtons) { - QuizController.Question current = quizController.getCurrentQuestion(); - if (current != null) { - numberLabel.setText("第 " + quizController.getCurrentQuestionNumber() + - " 题 / 共 " + quizController.getTotalQuestions() + " 题"); - contentLabel.setText("" + current.getContent() + ""); + panel.add(infoPanel, BorderLayout.NORTH); + panel.add(scrollPane, BorderLayout.CENTER); + panel.add(buttonPanel, BorderLayout.SOUTH); - String[] options = current.getOptions(); - for (int i = 0; i < 4; i++) { - optionButtons[i].setText((char) ('A' + i) + ". " + options[i]); + return panel; + } + + public JPanel buildScoreView(int score, int total, double percentage, Runnable continueAction) { + JPanel panel = new JPanel(); + panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS)); + panel.setBorder(BorderFactory.createEmptyBorder(40, 40, 40, 40)); + + JLabel titleLabel = new JLabel("答题完成!"); + titleLabel.setFont(new Font("微软雅黑", Font.BOLD, 24)); + titleLabel.setAlignmentX(Component.CENTER_ALIGNMENT); + + JLabel scoreLabel = new JLabel("得分: " + score + "/" + total); + scoreLabel.setFont(new Font("微软雅黑", Font.PLAIN, 18)); + scoreLabel.setAlignmentX(Component.CENTER_ALIGNMENT); + + JLabel percentageLabel = new JLabel("正确率: " + String.format("%.1f", percentage) + "%"); + percentageLabel.setFont(new Font("微软雅黑", Font.PLAIN, 16)); + percentageLabel.setAlignmentX(Component.CENTER_ALIGNMENT); + + if (percentage >= 80) { + percentageLabel.setForeground(new Color(76, 175, 80)); + } else if (percentage >= 60) { + percentageLabel.setForeground(new Color(255, 152, 0)); + } else { + percentageLabel.setForeground(new Color(244, 67, 54)); } + + JPanel buttonPanel = new JPanel(); + buttonPanel.setLayout(new FlowLayout()); + buttonPanel.setAlignmentX(Component.CENTER_ALIGNMENT); + + JButton continueButton = createStyledButton("继续做题", new Color(76, 175, 80), 120, 35); + + continueButton.addActionListener(e -> continueAction.run()); + + buttonPanel.add(continueButton); + + panel.add(Box.createVerticalStrut(20)); + panel.add(titleLabel); + panel.add(Box.createVerticalStrut(30)); + panel.add(scoreLabel); + panel.add(Box.createVerticalStrut(10)); + panel.add(percentageLabel); + panel.add(Box.createVerticalStrut(40)); + panel.add(buttonPanel); + + return panel; } - } - // 分数界面 - 完全保持不变 - private void showScoreView() { - JPanel mainPanel = new JPanel(); - mainPanel.setLayout(new BoxLayout(mainPanel, BoxLayout.Y_AXIS)); - mainPanel.setBorder(BorderFactory.createEmptyBorder(40, 40, 40, 40)); + public JPanel buildChangePasswordView(PasswordChangeListener changeListener, Runnable backAction) { + JPanel panel = new JPanel(); + panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS)); + panel.setBorder(BorderFactory.createEmptyBorder(30, 30, 30, 30)); + + JLabel titleLabel = new JLabel("修改密码"); + titleLabel.setFont(new Font("微软雅黑", Font.BOLD, 20)); + titleLabel.setAlignmentX(Component.CENTER_ALIGNMENT); + + JPanel inputPanel = new JPanel(); + inputPanel.setLayout(new BoxLayout(inputPanel, BoxLayout.Y_AXIS)); + inputPanel.setAlignmentX(Component.CENTER_ALIGNMENT); + + JPasswordField oldPasswordField = new JPasswordField(20); + JPasswordField newPasswordField = new JPasswordField(20); + JPasswordField confirmPasswordField = new JPasswordField(20); + + JPanel oldPasswordPanel = createLabelFieldPanel("原密码:", oldPasswordField); + JPanel newPasswordPanel = createLabelFieldPanel("新密码:", newPasswordField); + JPanel confirmPasswordPanel = createLabelFieldPanel("确认密码:", confirmPasswordField); + + inputPanel.add(oldPasswordPanel); + inputPanel.add(Box.createVerticalStrut(15)); + inputPanel.add(newPasswordPanel); + inputPanel.add(Box.createVerticalStrut(15)); + inputPanel.add(confirmPasswordPanel); + + // 添加消息标签 + JLabel messageLabel = new JLabel(" "); + messageLabel.setAlignmentX(Component.CENTER_ALIGNMENT); + messageLabel.setForeground(Color.RED); + + JPanel buttonPanel = new JPanel(); + buttonPanel.setLayout(new FlowLayout()); + buttonPanel.setAlignmentX(Component.CENTER_ALIGNMENT); + + JButton submitButton = createStyledButton("确认修改", new Color(76, 175, 80), 120, 35); + JButton backButton = createStyledButton("返回", new Color(158, 158, 158), 120, 35); + + submitButton.addActionListener(e -> { + String oldPassword = new String(oldPasswordField.getPassword()); + String newPassword = new String(newPasswordField.getPassword()); + String confirmPassword = new String(confirmPasswordField.getPassword()); + + // 客户端验证 + if (oldPassword.isEmpty() || newPassword.isEmpty() || confirmPassword.isEmpty()) { + messageLabel.setText("请填写所有密码字段!"); + messageLabel.setForeground(Color.RED); + return; + } - JLabel titleLabel = new JLabel("答题完成!"); - titleLabel.setFont(new Font("微软雅黑", Font.BOLD, 24)); - titleLabel.setAlignmentX(Component.CENTER_ALIGNMENT); + if (!newPassword.equals(confirmPassword)) { + messageLabel.setText("两次输入的新密码不一致!"); + messageLabel.setForeground(Color.RED); + return; + } - int score = quizController.getScore(); - int total = quizController.getTotalQuestions(); - double percentage = quizController.getPercentage(); + // 调用控制器处理密码修改 + boolean success = changeListener.onPasswordChange(oldPassword, newPassword, confirmPassword); + + if (success) { + messageLabel.setText("密码修改成功!"); + messageLabel.setForeground(Color.GREEN); + // 清空密码框 + oldPasswordField.setText(""); + newPasswordField.setText(""); + confirmPasswordField.setText(""); + } else { + messageLabel.setText("密码修改失败!请检查原密码是否正确,新密码是否符合要求。"); + messageLabel.setForeground(Color.RED); + } + }); + + backButton.addActionListener(e -> backAction.run()); - JLabel scoreLabel = new JLabel("得分: " + score + "/" + total); - scoreLabel.setFont(new Font("微软雅黑", Font.PLAIN, 18)); - scoreLabel.setAlignmentX(Component.CENTER_ALIGNMENT); + buttonPanel.add(submitButton); + buttonPanel.add(Box.createHorizontalStrut(20)); + buttonPanel.add(backButton); - JLabel percentageLabel = new JLabel("正确率: " + String.format("%.1f", percentage) + "%"); - percentageLabel.setFont(new Font("微软雅黑", Font.PLAIN, 16)); - percentageLabel.setAlignmentX(Component.CENTER_ALIGNMENT); + panel.add(Box.createVerticalStrut(10)); + panel.add(titleLabel); + panel.add(Box.createVerticalStrut(25)); + panel.add(inputPanel); + panel.add(Box.createVerticalStrut(15)); + panel.add(messageLabel); // 添加消息标签到面板 + panel.add(Box.createVerticalStrut(10)); + panel.add(buttonPanel); - if (percentage >= 80) { - percentageLabel.setForeground(new Color(76, 175, 80)); - } else if (percentage >= 60) { - percentageLabel.setForeground(new Color(255, 152, 0)); - } else { - percentageLabel.setForeground(new Color(244, 67, 54)); + return panel; } - JPanel buttonPanel = new JPanel(); - buttonPanel.setLayout(new FlowLayout()); - buttonPanel.setAlignmentX(Component.CENTER_ALIGNMENT); - - JButton continueButton = new JButton("继续做题"); - continueButton.setBackground(new Color(76, 175, 80)); - continueButton.setForeground(Color.WHITE); - continueButton.setPreferredSize(new Dimension(120, 35)); - continueButton.setOpaque(true); - continueButton.setBorderPainted(false); - continueButton.setFocusPainted(false); - - JButton exitButton = new JButton("退出"); - exitButton.setBackground(new Color(158, 158, 158)); - exitButton.setForeground(Color.WHITE); - exitButton.setPreferredSize(new Dimension(120, 35)); - exitButton.setOpaque(true); - exitButton.setBorderPainted(false); - exitButton.setFocusPainted(false); - - buttonPanel.add(continueButton); - buttonPanel.add(Box.createHorizontalStrut(20)); - buttonPanel.add(exitButton); - - mainPanel.add(Box.createVerticalStrut(20)); - mainPanel.add(titleLabel); - mainPanel.add(Box.createVerticalStrut(30)); - mainPanel.add(scoreLabel); - mainPanel.add(Box.createVerticalStrut(10)); - mainPanel.add(percentageLabel); - mainPanel.add(Box.createVerticalStrut(40)); - mainPanel.add(buttonPanel); - - continueButton.addActionListener(e -> showMainView()); - exitButton.addActionListener(e -> showMainView()); + // ==================== 辅助方法 ==================== - mainFrame.setContentPane(mainPanel); - mainFrame.revalidate(); - mainFrame.repaint(); + private JPanel createLabelFieldPanel(String labelText, JComponent field) { + JPanel panel = new JPanel(new FlowLayout(FlowLayout.LEFT)); + panel.add(new JLabel(labelText)); + panel.add(field); + return panel; + } + + private JButton createStyledButton(String text, Color color, int width, int height) { + JButton button = new JButton(text); + button.setBackground(color); + button.setForeground(Color.WHITE); + button.setPreferredSize(new Dimension(width, height)); + button.setOpaque(true); + button.setBorderPainted(false); + button.setFocusPainted(false); + return button; + } + + private JButton createDifficultyButton(String text, Color color) { + JButton button = createStyledButton(text, color, 140, 45); + button.setFont(new Font("微软雅黑", Font.BOLD, 16)); + button.setMaximumSize(new Dimension(140, 45)); + button.setAlignmentX(Component.CENTER_ALIGNMENT); + return button; + } } - // 修改密码界面 - 完全保持不变 - private void showChangePasswordView() { - JPanel mainPanel = new JPanel(); - mainPanel.setLayout(new BoxLayout(mainPanel, BoxLayout.Y_AXIS)); - mainPanel.setBorder(BorderFactory.createEmptyBorder(30, 30, 30, 30)); - - JLabel titleLabel = new JLabel("修改密码"); - titleLabel.setFont(new Font("微软雅黑", Font.BOLD, 20)); - titleLabel.setAlignmentX(Component.CENTER_ALIGNMENT); - - JPanel inputPanel = new JPanel(); - inputPanel.setLayout(new BoxLayout(inputPanel, BoxLayout.Y_AXIS)); - inputPanel.setAlignmentX(Component.CENTER_ALIGNMENT); - - JPanel oldPasswordPanel = new JPanel(new FlowLayout(FlowLayout.LEFT)); - JLabel oldPasswordLabel = new JLabel("原密码:"); - JPasswordField oldPasswordField = new JPasswordField(20); - oldPasswordField.setPreferredSize(new Dimension(200, 30)); - oldPasswordPanel.add(oldPasswordLabel); - oldPasswordPanel.add(oldPasswordField); - - JPanel newPasswordPanel = new JPanel(new FlowLayout(FlowLayout.LEFT)); - JLabel newPasswordLabel = new JLabel("新密码:"); - JPasswordField newPasswordField = new JPasswordField(20); - newPasswordField.setPreferredSize(new Dimension(200, 30)); - newPasswordPanel.add(newPasswordLabel); - newPasswordPanel.add(newPasswordField); - - JPanel confirmPasswordPanel = new JPanel(new FlowLayout(FlowLayout.LEFT)); - JLabel confirmPasswordLabel = new JLabel("确认密码:"); - JPasswordField confirmPasswordField = new JPasswordField(20); - confirmPasswordField.setPreferredSize(new Dimension(200, 30)); - confirmPasswordPanel.add(confirmPasswordLabel); - confirmPasswordPanel.add(confirmPasswordField); - - inputPanel.add(oldPasswordPanel); - inputPanel.add(Box.createVerticalStrut(15)); - inputPanel.add(newPasswordPanel); - inputPanel.add(Box.createVerticalStrut(15)); - inputPanel.add(confirmPasswordPanel); - - JPanel buttonPanel = new JPanel(); - buttonPanel.setLayout(new FlowLayout()); - buttonPanel.setAlignmentX(Component.CENTER_ALIGNMENT); - - JButton submitButton = new JButton("确认修改"); - submitButton.setBackground(new Color(76, 175, 80)); - submitButton.setForeground(Color.WHITE); - submitButton.setPreferredSize(new Dimension(120, 35)); - submitButton.setOpaque(true); - submitButton.setBorderPainted(false); - submitButton.setFocusPainted(false); - - JButton backButton = new JButton("返回"); - backButton.setBackground(new Color(158, 158, 158)); - backButton.setForeground(Color.WHITE); - backButton.setPreferredSize(new Dimension(120, 35)); - backButton.setOpaque(true); - backButton.setBorderPainted(false); - backButton.setFocusPainted(false); - - buttonPanel.add(submitButton); - buttonPanel.add(Box.createHorizontalStrut(20)); - buttonPanel.add(backButton); - - JLabel messageLabel = new JLabel(" "); - messageLabel.setAlignmentX(Component.CENTER_ALIGNMENT); - messageLabel.setForeground(Color.RED); - - mainPanel.add(Box.createVerticalStrut(10)); - mainPanel.add(titleLabel); - mainPanel.add(Box.createVerticalStrut(25)); - mainPanel.add(inputPanel); - mainPanel.add(Box.createVerticalStrut(25)); - mainPanel.add(buttonPanel); - mainPanel.add(Box.createVerticalStrut(20)); - mainPanel.add(messageLabel); - - submitButton.addActionListener(e -> { - String oldPassword = new String(oldPasswordField.getPassword()); - String newPassword = new String(newPasswordField.getPassword()); - String confirmPassword = new String(confirmPasswordField.getPassword()); + /** + * 事件处理器 - 负责管理事件监听 + */ + private class EventHandlers { + // 可以在这里添加复杂的事件处理逻辑 + // 目前事件处理直接在内联监听器中实现 + } - if (!newPassword.equals(confirmPassword)) { - messageLabel.setText("两次输入的新密码不一致!"); - messageLabel.setForeground(Color.RED); - return; - } + // ========================================================================= + // 监听器接口定义 + // ========================================================================= - if (!userManager.isValidPassword(newPassword)) { - messageLabel.setText("密码不符合要求:
- 长度必须在6-10位之间
- 必须包含大写字母、小写字母和数字"); - messageLabel.setForeground(Color.RED); - return; - } + private interface LoginListener { + void onLogin(String email, String password); + } - if (userManager.changePassword(oldPassword, newPassword)) { - messageLabel.setText("密码修改成功!"); - messageLabel.setForeground(Color.GREEN); - } else { - messageLabel.setText("密码修改失败!请检查原密码是否正确,新密码是否符合要求。"); - messageLabel.setForeground(Color.RED); - } - }); + private interface SendCodeListener { + boolean onSendCode(String username, String email); + } - backButton.addActionListener(e -> showMainView()); + private interface RegisterListener { + boolean onRegister(String username, String email, String code, String password, String confirmPassword); + } - mainFrame.setContentPane(mainPanel); - mainFrame.revalidate(); - mainFrame.repaint(); + private interface DifficultySelectListener { + void onDifficultySelected(String difficulty); } - private boolean isValidEmail(String email) { - String emailRegex = "^[a-zA-Z0-9_+&*-]+(?:\\.[a-zA-Z0-9_+&*-]+)*@(?:[a-zA-Z0-9-]+\\.)+[a-zA-Z]{2,7}$"; - return email != null && email.matches(emailRegex); + private interface CountSubmitListener { + void onCountSubmit(int count); + } + + private interface AnswerSubmitListener { + void onAnswerSubmit(int answer); + } + + private interface PasswordChangeListener { + boolean onPasswordChange(String oldPassword, String newPassword, String confirmPassword); } } \ No newline at end of file