From eecf589782557400822af8a80afb5fa31c8dff73 Mon Sep 17 00:00:00 2001 From: chen <3602749708@qq.com> Date: Fri, 10 Oct 2025 12:22:03 +0800 Subject: [PATCH] =?UTF-8?q?=E5=88=9D=E7=89=88?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/MathLearningApp.java | 19 +++ src/controller/NavigationController.java | 87 ++++++++++++ src/controller/QuestionController.java | 96 +++++++++++++ src/controller/UserController.java | 112 +++++++++++++++ src/model/Question.java | 37 +++++ src/model/QuestionGenerator.java | 154 +++++++++++++++++++++ src/model/User.java | 32 +++++ src/utils/EmailUtil.java | 107 ++++++++++++++ src/utils/FileUtil.java | 138 ++++++++++++++++++ src/utils/ValidationUtil.java | 39 ++++++ src/view/ChangePasswordDialog.java | 121 ++++++++++++++++ src/view/ExamView.java | 169 +++++++++++++++++++++++ src/view/LoginView.java | 106 ++++++++++++++ src/view/MainView.java | 113 +++++++++++++++ src/view/RegisterView.java | 151 ++++++++++++++++++++ src/view/ResultView.java | 69 +++++++++ 16 files changed, 1550 insertions(+) create mode 100644 src/MathLearningApp.java create mode 100644 src/controller/NavigationController.java create mode 100644 src/controller/QuestionController.java create mode 100644 src/controller/UserController.java create mode 100644 src/model/Question.java create mode 100644 src/model/QuestionGenerator.java create mode 100644 src/model/User.java create mode 100644 src/utils/EmailUtil.java create mode 100644 src/utils/FileUtil.java create mode 100644 src/utils/ValidationUtil.java create mode 100644 src/view/ChangePasswordDialog.java create mode 100644 src/view/ExamView.java create mode 100644 src/view/LoginView.java create mode 100644 src/view/MainView.java create mode 100644 src/view/RegisterView.java create mode 100644 src/view/ResultView.java diff --git a/src/MathLearningApp.java b/src/MathLearningApp.java new file mode 100644 index 0000000..3f0ec15 --- /dev/null +++ b/src/MathLearningApp.java @@ -0,0 +1,19 @@ +import controller.NavigationController; +import javax.swing.*; + +public class MathLearningApp { + public static void main(String[] args) { + // Set system look and feel + try { + + UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); + } catch (Exception e) { + e.printStackTrace(); + } + + // Start the application + SwingUtilities.invokeLater(() -> { + NavigationController.showLoginView(); + }); + } +} \ No newline at end of file diff --git a/src/controller/NavigationController.java b/src/controller/NavigationController.java new file mode 100644 index 0000000..5db5105 --- /dev/null +++ b/src/controller/NavigationController.java @@ -0,0 +1,87 @@ +package controller; + +import model.User; +import view.*; + +public class NavigationController { + private static LoginView loginView; + private static RegisterView registerView; + private static MainView mainView; + private static ExamView examView; + private static ResultView resultView; + private static User currentUser; // 保存当前登录用户 + + public static void showLoginView() { + if (loginView == null) { + loginView = new LoginView(); + } + loginView.setVisible(true); + hideAllExcept(loginView); + } + + public static void showRegisterView() { + if (registerView == null) { + registerView = new RegisterView(); + } + registerView.setVisible(true); + hideAllExcept(registerView); + } + + // 修改:传递用户信息到主界面 + public static void showMainView(User user) { + currentUser = user; + if (mainView != null) { + mainView.dispose(); // 关闭旧的主界面 + } + mainView = new MainView(user); // 创建新的主界面 + mainView.setVisible(true); + hideAllExcept(mainView); + } + + // 新增:无参数版本,使用当前保存的用户 + public static void showMainView() { + if (currentUser != null) { + showMainView(currentUser); + } else { + // 如果没有保存的用户,返回登录界面 + showLoginView(); + } + } + + public static void showExamView(String difficulty, int questionCount) { + if (examView == null) { + examView = new ExamView(); + } + examView.startNewExam(difficulty, questionCount); + examView.setVisible(true); + hideAllExcept(examView); + } + + public static void showResultView(int score, int total, double percentage) { + if (resultView == null) { + resultView = new ResultView(); + } + resultView.setResults(score, total, percentage); + resultView.setVisible(true); + hideAllExcept(resultView); + } + + private static void hideAllExcept(javax.swing.JFrame visibleFrame) { + javax.swing.JFrame[] frames = {loginView, registerView, mainView, examView, resultView}; + for (javax.swing.JFrame frame : frames) { + if (frame != null && frame != visibleFrame) { + frame.setVisible(false); + } + } + } + + // 新增:设置当前用户(在登录时调用) + public static void setCurrentUser(User user) { + currentUser = user; + } + + // 新增:获取当前用户 + public static User getCurrentUser() { + return currentUser; + } +} \ No newline at end of file diff --git a/src/controller/QuestionController.java b/src/controller/QuestionController.java new file mode 100644 index 0000000..5770bf9 --- /dev/null +++ b/src/controller/QuestionController.java @@ -0,0 +1,96 @@ +package controller; + +import model.Question; +import model.QuestionGenerator; +import utils.FileUtil; +import java.util.*; + +public class QuestionController { + private QuestionGenerator generator = new QuestionGenerator(); + private List currentQuestions; + private int currentQuestionIndex = 0; + private int score = 0; + private int[] userAnswers; + private String currentDifficulty; + private int currentQuestionCount; + + public void startNewExam(String difficulty, int questionCount) { + currentQuestions = generator.generateQuestions(questionCount, difficulty); + currentQuestionIndex = 0; + score = 0; + userAnswers = new int[questionCount]; + Arrays.fill(userAnswers, -1); + currentDifficulty = difficulty; + currentQuestionCount = questionCount; + + // 保存试卷到本地 + FileUtil.saveCurrentExam(currentQuestions, difficulty, questionCount); + + System.out.println("🎯 生成新试卷: " + difficulty + " 难度, " + questionCount + " 道题"); + } + + + + /** + * 获取当前试卷信息 + */ + public String getCurrentExamInfo() { + if (currentDifficulty != null && currentQuestionCount > 0) { + return currentDifficulty + "难度 - " + currentQuestionCount + "道题"; + } + return "暂无试卷"; + } + + // 其他方法保持不变... + public Question getCurrentQuestion() { + if (currentQuestions == null || currentQuestionIndex >= currentQuestions.size()) { + return null; + } + return currentQuestions.get(currentQuestionIndex); + } + + public void submitAnswer(int answer) { + if (currentQuestionIndex < userAnswers.length) { + userAnswers[currentQuestionIndex] = answer; + } + } + + public boolean nextQuestion() { + currentQuestionIndex++; + return currentQuestionIndex < currentQuestions.size(); + } + + public boolean previousQuestion() { + if (currentQuestionIndex > 0) { + currentQuestionIndex--; + return true; + } + return false; + } + + public int calculateScore() { + score = 0; + for (int i = 0; i < currentQuestions.size(); i++) { + if (userAnswers[i] != -1 && currentQuestions.get(i).isCorrect(userAnswers[i])) { + score++; + } + } + return score; + } + + public double getPercentage() { + return (double) score / currentQuestions.size() * 100; + } + + public int getCurrentQuestionNumber() { + return currentQuestionIndex + 1; + } + + public int getTotalQuestions() { + return currentQuestions != null ? currentQuestions.size() : 0; + } + + public int getUserAnswerForCurrentQuestion() { + return userAnswers[currentQuestionIndex]; + } +} \ No newline at end of file diff --git a/src/controller/UserController.java b/src/controller/UserController.java new file mode 100644 index 0000000..1eb479d --- /dev/null +++ b/src/controller/UserController.java @@ -0,0 +1,112 @@ +package controller; + +import model.User; +import utils.*; + +public class UserController { + + /** + * 注册用户 - 发送注册码 + */ + public String registerUser(String username, String email) { + // 验证用户名 + if (username == null || username.trim().isEmpty()) { + return "用户名不能为空"; + } + if (username.length() < 2 || username.length() > 20) { + return "用户名长度应为2-20个字符"; + } + + // 验证邮箱 + if (!ValidationUtil.isValidEmail(email)) { + return "邮箱格式不正确"; + } + + // 检查用户名是否已存在 + if (FileUtil.usernameExists(username)) { + return "用户名已被使用"; + } + + // 检查邮箱是否已注册 + if (FileUtil.emailExists(email)) { + return "该邮箱已被注册"; + } + + // 生成注册码 + String registrationCode = EmailUtil.generateRegistrationCode(); + User user = new User(username, email, registrationCode); + + // 发送注册码到邮箱 + boolean sendSuccess = EmailUtil.sendRegistrationCode(email, username, registrationCode); + + if (sendSuccess) { + // 保存用户信息 + FileUtil.saveUser(user); + return "注册码已发送到您的邮箱,请查收!"; + } else { + return "邮件发送失败,请检查邮箱地址或稍后重试"; + } + } + + /** + * 完成注册 - 设置密码 + */ + public String completeRegistration(String username, String code, String password, String confirmPassword) { + User user = FileUtil.loadUserByUsername(username); + + if (user == null) { + return "用户不存在或注册码未发送"; + } + + if (!user.getRegistrationCode().equals(code)) { + return "注册码不正确"; + } + + if (!password.equals(confirmPassword)) { + return "两次输入的密码不一致"; + } + + if (!ValidationUtil.isValidPassword(password)) { + return "密码必须为6-10位,且包含大小写字母和数字"; + } + + user.setPassword(password); + user.setRegistered(true); + FileUtil.saveUser(user); + + return "注册成功!"; + } + + /** + * 用户登录 - 使用用户名登录 + */ + public User login(String username, String password) { + User user = FileUtil.loadUserByUsername(username); + if (user != null && user.isRegistered() && user.getPassword().equals(password)) { + return user; + } + return null; + } + + /** + * 修改密码 + */ + public String changePassword(User user, String oldPassword, String newPassword, String confirmPassword) { + if (!user.getPassword().equals(oldPassword)) { + return "原密码不正确"; + } + + if (!newPassword.equals(confirmPassword)) { + return "两次输入的新密码不一致"; + } + + if (!ValidationUtil.isValidPassword(newPassword)) { + return "新密码必须为6-10位,且包含大小写字母和数字"; + } + + user.setPassword(newPassword); + FileUtil.saveUser(user); + return "密码修改成功"; + } + +} \ No newline at end of file diff --git a/src/model/Question.java b/src/model/Question.java new file mode 100644 index 0000000..0538b2e --- /dev/null +++ b/src/model/Question.java @@ -0,0 +1,37 @@ +package model; + +import java.io.Serializable; + +public class Question implements Serializable { + private static final long serialVersionUID = 1L; + + private String question; + private String[] options; + private int correctAnswer; + private String difficulty; + + public Question(String question, String[] options, int correctAnswer, String difficulty) { + this.question = question; + this.options = options; + this.correctAnswer = correctAnswer; + this.difficulty = difficulty; + } + + // Getters + public String getQuestion() { return question; } + public String[] getOptions() { return options; } + public int getCorrectAnswer() { return correctAnswer; } + public String getDifficulty() { return difficulty; } + + public boolean isCorrect(int selectedAnswer) { + return selectedAnswer == correctAnswer; + } + + @Override + public String toString() { + return "Question{" + + "question='" + question + '\'' + + ", difficulty='" + difficulty + '\'' + + '}'; + } +} \ No newline at end of file diff --git a/src/model/QuestionGenerator.java b/src/model/QuestionGenerator.java new file mode 100644 index 0000000..c4e3e92 --- /dev/null +++ b/src/model/QuestionGenerator.java @@ -0,0 +1,154 @@ +package model; + +import java.util.*; + +public class QuestionGenerator { + private Random random = new Random(); + + public List generateQuestions(int count, String difficulty) { + List questions = new ArrayList<>(); + Set existingQuestions = new HashSet<>(); + + while (questions.size() < count) { + Question question = generateQuestion(difficulty); + String questionKey = question.getQuestion() + Arrays.toString(question.getOptions()); + + if (!existingQuestions.contains(questionKey)) { + questions.add(question); + existingQuestions.add(questionKey); + } + } + + return questions; + } + + private Question generateQuestion(String difficulty) { + switch (difficulty) { + case "小学": + return generatePrimaryQuestion(); + case "初中": + return generateMiddleSchoolQuestion(); + case "高中": + return generateHighSchoolQuestion(); + default: + return generatePrimaryQuestion(); + } + } + + private Question generatePrimaryQuestion() { + int num1 = random.nextInt(50) + 1; + int num2 = random.nextInt(50) + 1; + char[] operators = {'+', '-', '*', '/'}; + char operator = operators[random.nextInt(operators.length)]; + + String question; + double correctAnswer; + + switch (operator) { + case '+': + correctAnswer = num1 + num2; + question = num1 + " + " + num2 + " = ?"; + break; + case '-': + correctAnswer = num1 - num2; + question = num1 + " - " + num2 + " = ?"; + break; + case '*': + correctAnswer = num1 * num2; + question = num1 + " × " + num2 + " = ?"; + break; + case '/': + num2 = random.nextInt(10) + 1; // Avoid division by zero + correctAnswer = (double) num1 / num2; + question = num1 + " ÷ " + num2 + " = ?"; + break; + default: + correctAnswer = 0; + question = ""; + } + + String[] options = generateOptions(correctAnswer); + return new Question(question, options, getCorrectOptionIndex(options, correctAnswer), "小学"); + } + + private Question generateMiddleSchoolQuestion() { + int num = random.nextInt(20) + 1; + String question; + double correctAnswer; + + if (random.nextBoolean()) { + // Square question + correctAnswer = Math.pow(num, 2); + question = num + "² = ?"; + } else { + // Square root question + int squared = num * num; + correctAnswer = num; + question = "√" + squared + " = ?"; + } + + String[] options = generateOptions(correctAnswer); + return new Question(question, options, getCorrectOptionIndex(options, correctAnswer), "初中"); + } + + private Question generateHighSchoolQuestion() { + double angle = random.nextInt(360); + String[] trigFunctions = {"sin", "cos", "tan"}; + String trigFunction = trigFunctions[random.nextInt(trigFunctions.length)]; + + String question; + double correctAnswer; + + switch (trigFunction) { + case "sin": + correctAnswer = Math.sin(Math.toRadians(angle)); + question = "sin(" + angle + "°) = ?"; + break; + case "cos": + correctAnswer = Math.cos(Math.toRadians(angle)); + question = "cos(" + angle + "°) = ?"; + break; + case "tan": + correctAnswer = Math.tan(Math.toRadians(angle)); + question = "tan(" + angle + "°) = ?"; + break; + default: + correctAnswer = 0; + question = ""; + } + + // Round to 2 decimal places + correctAnswer = Math.round(correctAnswer * 100.0) / 100.0; + String[] options = generateOptions(correctAnswer); + return new Question(question, options, getCorrectOptionIndex(options, correctAnswer), "高中"); + } + + private String[] generateOptions(double correctAnswer) { + String[] options = new String[4]; + int correctIndex = random.nextInt(4); + + for (int i = 0; i < 4; i++) { + if (i == correctIndex) { + options[i] = String.valueOf(correctAnswer); + } else { + double wrongAnswer; + do { + double variation = (random.nextDouble() - 0.5) * 10; + wrongAnswer = Math.round((correctAnswer + variation) * 100.0) / 100.0; + } while (Math.abs(wrongAnswer - correctAnswer) < 0.1); + options[i] = String.valueOf(wrongAnswer); + } + } + + return options; + } + + private int getCorrectOptionIndex(String[] options, double correctAnswer) { + for (int i = 0; i < options.length; i++) { + if (Double.parseDouble(options[i]) == correctAnswer) { + return i; + } + } + return 0; + } +} \ No newline at end of file diff --git a/src/model/User.java b/src/model/User.java new file mode 100644 index 0000000..b0dff55 --- /dev/null +++ b/src/model/User.java @@ -0,0 +1,32 @@ +package model; + +public class User { + private String username; // 新增:用户名 + private String email; + private String password; + private String registrationCode; + private boolean isRegistered; + + public User(String username, String email, String registrationCode) { + this.username = username; + this.email = email; + this.registrationCode = registrationCode; + this.isRegistered = false; + } + + // Getters and Setters + public String getUsername() { return username; } + public void setUsername(String username) { this.username = username; } + + public String getEmail() { return email; } + public void setEmail(String email) { this.email = email; } + + public String getPassword() { return password; } + public void setPassword(String password) { this.password = password; } + + public String getRegistrationCode() { return registrationCode; } + public void setRegistrationCode(String registrationCode) { this.registrationCode = registrationCode; } + + public boolean isRegistered() { return isRegistered; } + public void setRegistered(boolean registered) { isRegistered = registered; } +} \ No newline at end of file diff --git a/src/utils/EmailUtil.java b/src/utils/EmailUtil.java new file mode 100644 index 0000000..e0d0930 --- /dev/null +++ b/src/utils/EmailUtil.java @@ -0,0 +1,107 @@ +package utils; + +import javax.mail.*; +import javax.mail.internet.*; +import java.util.Properties; +import java.util.Random; + +public class EmailUtil { + private static final Random random = new Random(); + + // SMTP服务器配置 - 请修改为您的邮箱配置 + private static final String SMTP_HOST = "smtp.qq.com"; // QQ邮箱SMTP + private static final String SMTP_PORT = "587"; // 端口 + private static final String FROM_EMAIL = "2536082954@qq.com"; // 发件邮箱 + private static final String EMAIL_PASSWORD = "uihuasdsosbvdiia"; // 授权码 + private static final String FROM_NAME = "数学学习软件"; + + public static String generateRegistrationCode() { + return String.format("%06d", random.nextInt(1000000)); + } + + /** + * 发送注册码到用户输入的邮箱 + */ + public static boolean sendRegistrationCode(String userEmail, String username, String code) { + // 配置邮件服务器 + Properties props = new Properties(); + props.put("mail.smtp.auth", "true"); + props.put("mail.smtp.starttls.enable", "true"); + props.put("mail.smtp.host", SMTP_HOST); + props.put("mail.smtp.port", SMTP_PORT); + + // 超时设置 + props.put("mail.smtp.timeout", "10000"); + props.put("mail.smtp.connectiontimeout", "10000"); + + // 创建认证器 + Authenticator authenticator = new Authenticator() { + @Override + protected PasswordAuthentication getPasswordAuthentication() { + return new PasswordAuthentication(FROM_EMAIL, EMAIL_PASSWORD); + } + }; + + Session session = Session.getInstance(props, authenticator); + + try { + // 创建邮件 + MimeMessage message = new MimeMessage(session); + message.setFrom(new InternetAddress(FROM_EMAIL, FROM_NAME, "UTF-8")); + message.setRecipient(Message.RecipientType.TO, new InternetAddress(userEmail)); + message.setSubject("数学学习软件 - 注册验证码", "UTF-8"); + + // 邮件内容(HTML格式) + String htmlContent = buildEmailContent(username, code); + message.setContent(htmlContent, "text/html;charset=UTF-8"); + + // 发送邮件 + Transport.send(message); + System.out.println("✅ 注册码已成功发送到: " + userEmail); + return true; + + } catch (Exception e) { + System.err.println("❌ 邮件发送失败: " + e.getMessage()); + e.printStackTrace(); + return false; + } + } + + /** + * 构建邮件内容 + */ + private static String buildEmailContent(String username, String code) { + return "" + + "" + + "" + + " " + + " " + + "" + + "" + + "
" + + "
" + + "

数学学习软件 - 注册验证码

" + + "
" + + "

亲爱的 " + username + ",您好!

" + + "

您正在注册数学学习软件,请使用以下验证码完成注册:

" + + "
" + + "
" + code + "
" + + "
" + + "

验证码有效期30分钟,请尽快完成注册。

" + + "

如果这不是您的操作,请忽略此邮件。

" + + "
" + + "

此为系统邮件,请勿回复

" + + "

数学学习软件团队

" + + "
" + + "
" + + "" + + ""; + } +} \ No newline at end of file diff --git a/src/utils/FileUtil.java b/src/utils/FileUtil.java new file mode 100644 index 0000000..0de74de --- /dev/null +++ b/src/utils/FileUtil.java @@ -0,0 +1,138 @@ +package utils; + +import model.Question; +import model.User; +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.google.gson.reflect.TypeToken; +import java.io.*; +import java.lang.reflect.Type; +import java.util.*; + +public class FileUtil { + private static final String USERS_FILE = "data/users.json"; + private static final String CURRENT_EXAM_FILE = "data/current_exam.json"; + private static final Gson gson = new GsonBuilder().setPrettyPrinting().create(); + + static { + new File("data").mkdirs(); + } + + // 用户相关方法保持不变... + public static void saveUser(User user) { + try { + Map users = loadAllUsers(); + users.put(user.getUsername(), user); + + try (FileWriter writer = new FileWriter(USERS_FILE)) { + gson.toJson(users, writer); + } + } catch (IOException e) { + System.err.println("保存用户数据失败: " + e.getMessage()); + } + } + + public static Map loadAllUsers() { + try { + File file = new File(USERS_FILE); + if (!file.exists()) { + return new HashMap<>(); + } + + try (FileReader reader = new FileReader(file)) { + Type type = new TypeToken>(){}.getType(); + Map users = gson.fromJson(reader, type); + return users != null ? users : new HashMap<>(); + } + } catch (IOException e) { + System.err.println("加载用户数据失败: " + e.getMessage()); + return new HashMap<>(); + } + } + + public static User loadUserByUsername(String username) { + Map users = loadAllUsers(); + return users.get(username); + } + + public static User loadUserByEmail(String email) { + Map users = loadAllUsers(); + for (User user : users.values()) { + if (user.getEmail().equals(email)) { + return user; + } + } + return null; + } + + public static boolean usernameExists(String username) { + return loadAllUsers().containsKey(username); + } + + public static boolean emailExists(String email) { + return loadUserByEmail(email) != null; + } + + // ========== 试卷保存相关方法 ========== + + /** + * 保存当前试卷到本地文件(覆盖之前的试卷) + */ + public static void saveCurrentExam(List questions, String difficulty, int questionCount) { + try { + ExamData examData = new ExamData(questions, difficulty, questionCount, new Date()); + + try (FileWriter writer = new FileWriter(CURRENT_EXAM_FILE)) { + gson.toJson(examData, writer); + } + System.out.println("✅ 试卷已保存到本地: " + CURRENT_EXAM_FILE); + + } catch (IOException e) { + System.err.println("保存试卷失败: " + e.getMessage()); + } + } + + /** + * 从本地文件加载当前试卷 + */ + public static ExamData loadCurrentExam() { + try { + File file = new File(CURRENT_EXAM_FILE); + if (!file.exists()) { + return null; + } + + try (FileReader reader = new FileReader(file)) { + return gson.fromJson(reader, ExamData.class); + } + } catch (IOException e) { + System.err.println("加载试卷失败: " + e.getMessage()); + return null; + } + } + + + + /** + * 试卷数据包装类 + */ + public static class ExamData { + private List questions; + private String difficulty; + private int questionCount; + private Date generateTime; + + public ExamData(List questions, String difficulty, int questionCount, Date generateTime) { + this.questions = questions; + this.difficulty = difficulty; + this.questionCount = questionCount; + this.generateTime = generateTime; + } + + // Getters + public List getQuestions() { return questions; } + public String getDifficulty() { return difficulty; } + public int getQuestionCount() { return questionCount; } + public Date getGenerateTime() { return generateTime; } + } +} \ No newline at end of file diff --git a/src/utils/ValidationUtil.java b/src/utils/ValidationUtil.java new file mode 100644 index 0000000..54e454e --- /dev/null +++ b/src/utils/ValidationUtil.java @@ -0,0 +1,39 @@ +package utils; + +import java.util.regex.Pattern; + +public class ValidationUtil { + + public static boolean isValidEmail(String email) { + String emailRegex = "^[A-Za-z0-9+_.-]+@(.+)$"; + return Pattern.compile(emailRegex).matcher(email).matches(); + } + + public static boolean isValidPassword(String password) { + // 6-10位,必须包含大小写字母和数字 + if (password.length() < 6 || password.length() > 10) { + return false; + } + + boolean hasUpperCase = false; + boolean hasLowerCase = false; + boolean hasDigit = false; + + for (char c : password.toCharArray()) { + if (Character.isUpperCase(c)) hasUpperCase = true; + if (Character.isLowerCase(c)) hasLowerCase = true; + if (Character.isDigit(c)) hasDigit = true; + } + + return hasUpperCase && hasLowerCase && hasDigit; + } + + public static boolean isNumeric(String str) { + try { + Double.parseDouble(str); + return true; + } catch (NumberFormatException e) { + return false; + } + } +} diff --git a/src/view/ChangePasswordDialog.java b/src/view/ChangePasswordDialog.java new file mode 100644 index 0000000..01972f1 --- /dev/null +++ b/src/view/ChangePasswordDialog.java @@ -0,0 +1,121 @@ +package view; + +import controller.UserController; +import model.User; +import utils.ValidationUtil; + +import javax.swing.*; +import java.awt.*; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; + +public class ChangePasswordDialog extends JDialog { + private User currentUser; + private UserController userController; + + private JPasswordField oldPasswordField; + private JPasswordField newPasswordField; + private JPasswordField confirmPasswordField; + + public ChangePasswordDialog(JFrame parent, User user) { + super(parent, "修改密码", true); + this.currentUser = user; + this.userController = new UserController(); + initializeUI(); + } + + private void initializeUI() { + setSize(400, 300); + setLocationRelativeTo(getParent()); + setResizable(false); + + JPanel mainPanel = new JPanel(new BorderLayout(10, 10)); + mainPanel.setBorder(BorderFactory.createEmptyBorder(20, 20, 20, 20)); + + // Title + JLabel titleLabel = new JLabel("修改密码", JLabel.CENTER); + titleLabel.setFont(new Font("微软雅黑", Font.BOLD, 18)); + mainPanel.add(titleLabel, BorderLayout.NORTH); + + // Form panel + JPanel formPanel = new JPanel(new GridLayout(4, 2, 10, 10)); + + JLabel oldPasswordLabel = new JLabel("原密码:"); + oldPasswordLabel.setFont(new Font("微软雅黑", Font.PLAIN, 14)); + oldPasswordField = new JPasswordField(); + + JLabel newPasswordLabel = new JLabel("新密码:"); + newPasswordLabel.setFont(new Font("微软雅黑", Font.PLAIN, 14)); + newPasswordField = new JPasswordField(); + + JLabel confirmPasswordLabel = new JLabel("确认新密码:"); + confirmPasswordLabel.setFont(new Font("微软雅黑", Font.PLAIN, 14)); + confirmPasswordField = new JPasswordField(); + + JButton confirmButton = new JButton("确认修改"); + confirmButton.setFont(new Font("微软雅黑", Font.PLAIN, 14)); + + JButton cancelButton = new JButton("取消"); + cancelButton.setFont(new Font("微软雅黑", Font.PLAIN, 14)); + + formPanel.add(oldPasswordLabel); + formPanel.add(oldPasswordField); + formPanel.add(newPasswordLabel); + formPanel.add(newPasswordField); + formPanel.add(confirmPasswordLabel); + formPanel.add(confirmPasswordField); + formPanel.add(confirmButton); + formPanel.add(cancelButton); + + mainPanel.add(formPanel, BorderLayout.CENTER); + + // 密码要求提示 + JLabel hintLabel = new JLabel( + "" + + "密码要求:6-10位,必须包含大小写字母和数字
" + + "例如:Abc123、Test456" + + "", JLabel.CENTER); + hintLabel.setFont(new Font("微软雅黑", Font.PLAIN, 12)); + hintLabel.setForeground(Color.GRAY); + mainPanel.add(hintLabel, BorderLayout.SOUTH); + + // Add action listeners + confirmButton.addActionListener(new ConfirmAction()); + cancelButton.addActionListener(e -> dispose()); + + // Enter key support + oldPasswordField.addActionListener(new ConfirmAction()); + newPasswordField.addActionListener(new ConfirmAction()); + confirmPasswordField.addActionListener(new ConfirmAction()); + + add(mainPanel); + } + + private class ConfirmAction implements ActionListener { + @Override + public void actionPerformed(ActionEvent 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()) { + JOptionPane.showMessageDialog(ChangePasswordDialog.this, + "请填写所有密码字段", "错误", JOptionPane.ERROR_MESSAGE); + return; + } + + // 调用控制器修改密码 + String result = userController.changePassword(currentUser, oldPassword, newPassword, confirmPassword); + + if (result.equals("密码修改成功")) { + JOptionPane.showMessageDialog(ChangePasswordDialog.this, + "密码修改成功!", "成功", JOptionPane.INFORMATION_MESSAGE); + dispose(); // 关闭对话框 + } else { + JOptionPane.showMessageDialog(ChangePasswordDialog.this, + result, "错误", JOptionPane.ERROR_MESSAGE); + } + } + } +} \ No newline at end of file diff --git a/src/view/ExamView.java b/src/view/ExamView.java new file mode 100644 index 0000000..8f121f8 --- /dev/null +++ b/src/view/ExamView.java @@ -0,0 +1,169 @@ +package view; + +import controller.NavigationController; +import controller.QuestionController; +import model.Question; + +import javax.swing.*; +import java.awt.*; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; + +public class ExamView extends JFrame { + private QuestionController questionController; + private JLabel questionLabel; + private JLabel progressLabel; + private ButtonGroup optionGroup; + private JRadioButton[] optionButtons; + private JButton prevButton; + private JButton nextButton; + private JButton submitButton; + + public ExamView() { + questionController = new QuestionController(); + initializeUI(); + } + + private void initializeUI() { + setTitle("数学学习软件 - 答题界面"); + setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + setSize(600, 400); + setLocationRelativeTo(null); + setResizable(false); + + JPanel mainPanel = new JPanel(new BorderLayout(10, 10)); + mainPanel.setBorder(BorderFactory.createEmptyBorder(20, 20, 20, 20)); + + // Progress label + progressLabel = new JLabel("", JLabel.CENTER); + progressLabel.setFont(new Font("微软雅黑", Font.BOLD, 16)); + mainPanel.add(progressLabel, BorderLayout.NORTH); + + // Question panel + JPanel questionPanel = new JPanel(new BorderLayout(10, 10)); + questionLabel = new JLabel("", JLabel.CENTER); + questionLabel.setFont(new Font("微软雅黑", Font.PLAIN, 18)); + questionPanel.add(questionLabel, BorderLayout.NORTH); + + // Options panel + JPanel optionsPanel = new JPanel(new GridLayout(4, 1, 10, 10)); + optionGroup = new ButtonGroup(); + optionButtons = new JRadioButton[4]; + + for (int i = 0; i < 4; i++) { + optionButtons[i] = new JRadioButton(); + optionButtons[i].setFont(new Font("微软雅黑", Font.PLAIN, 14)); + optionGroup.add(optionButtons[i]); + optionsPanel.add(optionButtons[i]); + } + + questionPanel.add(optionsPanel, BorderLayout.CENTER); + mainPanel.add(questionPanel, BorderLayout.CENTER); + + // Button panel + JPanel buttonPanel = new JPanel(new FlowLayout()); + prevButton = new JButton("上一题"); + nextButton = new JButton("下一题"); + submitButton = new JButton("提交试卷"); + + prevButton.setFont(new Font("微软雅黑", Font.PLAIN, 14)); + nextButton.setFont(new Font("微软雅黑", Font.PLAIN, 14)); + submitButton.setFont(new Font("微软雅黑", Font.PLAIN, 14)); + + buttonPanel.add(prevButton); + buttonPanel.add(nextButton); + buttonPanel.add(submitButton); + + mainPanel.add(buttonPanel, BorderLayout.SOUTH); + + // Add action listeners + prevButton.addActionListener(new PrevButtonAction()); + nextButton.addActionListener(new NextButtonAction()); + submitButton.addActionListener(new SubmitButtonAction()); + + add(mainPanel); + } + + public void startNewExam(String difficulty, int questionCount) { + questionController.startNewExam(difficulty, questionCount); + displayCurrentQuestion(); + updateNavigationButtons(); + } + + private void displayCurrentQuestion() { + Question question = questionController.getCurrentQuestion(); + if (question == null) return; + + progressLabel.setText(String.format("第 %d 题 / 共 %d 题", + questionController.getCurrentQuestionNumber(), + questionController.getTotalQuestions())); + + questionLabel.setText(question.getQuestion()); + + String[] options = question.getOptions(); + for (int i = 0; i < 4; i++) { + optionButtons[i].setText((char)('A' + i) + ". " + options[i]); + } + + // Restore user's previous selection + int userAnswer = questionController.getUserAnswerForCurrentQuestion(); + optionGroup.clearSelection(); + if (userAnswer != -1) { + optionButtons[userAnswer].setSelected(true); + } + } + + private void updateNavigationButtons() { + int current = questionController.getCurrentQuestionNumber(); + int total = questionController.getTotalQuestions(); + + prevButton.setEnabled(current > 1); + nextButton.setEnabled(current < total); + submitButton.setEnabled(current == total); + } + + private void saveCurrentAnswer() { + for (int i = 0; i < 4; i++) { + if (optionButtons[i].isSelected()) { + questionController.submitAnswer(i); + break; + } + } + } + + private class PrevButtonAction implements ActionListener { + @Override + public void actionPerformed(ActionEvent e) { + saveCurrentAnswer(); + if (questionController.previousQuestion()) { + displayCurrentQuestion(); + updateNavigationButtons(); + } + } + } + + private class NextButtonAction implements ActionListener { + @Override + public void actionPerformed(ActionEvent e) { + saveCurrentAnswer(); + if (questionController.nextQuestion()) { + displayCurrentQuestion(); + updateNavigationButtons(); + } + } + } + + private class SubmitButtonAction implements ActionListener { + @Override + public void actionPerformed(ActionEvent e) { + saveCurrentAnswer(); + + int score = questionController.calculateScore(); + int total = questionController.getTotalQuestions(); + double percentage = questionController.getPercentage(); + + NavigationController.showResultView(score, total, percentage); + } + } + +} \ No newline at end of file diff --git a/src/view/LoginView.java b/src/view/LoginView.java new file mode 100644 index 0000000..4622a2b --- /dev/null +++ b/src/view/LoginView.java @@ -0,0 +1,106 @@ +package view; + +import controller.NavigationController; +import controller.UserController; +import model.User; + +import javax.swing.*; +import java.awt.*; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; + +public class LoginView extends JFrame { + private JTextField usernameField; // 新增:用户名字段 + private JPasswordField passwordField; + private UserController userController; + + public LoginView() { + userController = new UserController(); + initializeUI(); + } + + private void initializeUI() { + setTitle("数学学习软件 - 登录"); + setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + setSize(400, 300); + setLocationRelativeTo(null); + setResizable(false); + + JPanel mainPanel = new JPanel(new BorderLayout(10, 10)); + mainPanel.setBorder(BorderFactory.createEmptyBorder(20, 20, 20, 20)); + + // Title + JLabel titleLabel = new JLabel("用户登录", JLabel.CENTER); + titleLabel.setFont(new Font("微软雅黑", Font.BOLD, 24)); + mainPanel.add(titleLabel, BorderLayout.NORTH); + + // Form panel - 修改为用户名和密码 + JPanel formPanel = new JPanel(new GridLayout(3, 2, 10, 10)); + + JLabel usernameLabel = new JLabel("用户名:"); // 修改:改为用户名 + usernameLabel.setFont(new Font("微软雅黑", Font.PLAIN, 14)); + usernameField = new JTextField(); // 初始化用户名字段 + + JLabel passwordLabel = new JLabel("密码:"); + passwordLabel.setFont(new Font("微软雅黑", Font.PLAIN, 14)); + passwordField = new JPasswordField(); + + formPanel.add(usernameLabel); + formPanel.add(usernameField); + formPanel.add(passwordLabel); + formPanel.add(passwordField); + + // Buttons + JPanel buttonPanel = new JPanel(new FlowLayout()); + JButton loginButton = new JButton("登录"); + JButton registerButton = new JButton("注册"); + + loginButton.setFont(new Font("微软雅黑", Font.PLAIN, 14)); + registerButton.setFont(new Font("微软雅黑", Font.PLAIN, 14)); + + buttonPanel.add(loginButton); + buttonPanel.add(registerButton); + + formPanel.add(new JLabel()); // Empty cell + formPanel.add(buttonPanel); + + mainPanel.add(formPanel, BorderLayout.CENTER); + + // Add action listeners + loginButton.addActionListener(new LoginAction()); + registerButton.addActionListener(e -> { + NavigationController.showRegisterView(); + }); + + // Enter key support + usernameField.addActionListener(new LoginAction()); + passwordField.addActionListener(new LoginAction()); + + add(mainPanel); + } + + private class LoginAction implements ActionListener { + @Override + public void actionPerformed(ActionEvent e) { + String username = usernameField.getText().trim(); + String password = new String(passwordField.getPassword()); + + if (username.isEmpty() || password.isEmpty()) { + JOptionPane.showMessageDialog(LoginView.this, + "请输入用户名和密码", "错误", JOptionPane.ERROR_MESSAGE); + return; + } + + User user = userController.login(username, password); + if (user != null) { + JOptionPane.showMessageDialog(LoginView.this, + "登录成功!", "成功", JOptionPane.INFORMATION_MESSAGE); + // 修改:传递用户信息到主界面 + NavigationController.showMainView(user); + } else { + JOptionPane.showMessageDialog(LoginView.this, + "用户名或密码错误", "错误", JOptionPane.ERROR_MESSAGE); + } + } + } +} diff --git a/src/view/MainView.java b/src/view/MainView.java new file mode 100644 index 0000000..b16ae87 --- /dev/null +++ b/src/view/MainView.java @@ -0,0 +1,113 @@ +package view; + +import controller.NavigationController; +import controller.UserController; +import model.User; + +import javax.swing.*; +import java.awt.*; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; + +public class MainView extends JFrame { + private JComboBox difficultyComboBox; + private JTextField countField; + private User currentUser; // 保存当前登录用户 + + public MainView(User user) { + this.currentUser = user; + initializeUI(); + } + + private void initializeUI() { + setTitle("数学学习软件 - 主界面"); + setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + setSize(450, 350); + setLocationRelativeTo(null); + setResizable(false); + + JPanel mainPanel = new JPanel(new BorderLayout(10, 10)); + mainPanel.setBorder(BorderFactory.createEmptyBorder(20, 20, 20, 20)); + + // Title - 显示欢迎信息 + JLabel titleLabel = new JLabel("欢迎 " + currentUser.getUsername() + "!", JLabel.CENTER); + titleLabel.setFont(new Font("微软雅黑", Font.BOLD, 24)); + mainPanel.add(titleLabel, BorderLayout.NORTH); + + // Form panel + JPanel formPanel = new JPanel(new GridLayout(3, 2, 10, 10)); + + JLabel difficultyLabel = new JLabel("难度级别:"); + difficultyLabel.setFont(new Font("微软雅黑", Font.PLAIN, 14)); + String[] difficulties = {"小学", "初中", "高中"}; + difficultyComboBox = new JComboBox<>(difficulties); + difficultyComboBox.setFont(new Font("微软雅黑", Font.PLAIN, 14)); + + JLabel countLabel = new JLabel("题目数量:"); + countLabel.setFont(new Font("微软雅黑", Font.PLAIN, 14)); + countField = new JTextField("10"); + countField.setFont(new Font("微软雅黑", Font.PLAIN, 14)); + + JButton startButton = new JButton("开始答题"); + startButton.setFont(new Font("微软雅黑", Font.PLAIN, 14)); + + formPanel.add(difficultyLabel); + formPanel.add(difficultyComboBox); + formPanel.add(countLabel); + formPanel.add(countField); + formPanel.add(new JLabel()); // Empty cell + formPanel.add(startButton); + + mainPanel.add(formPanel, BorderLayout.CENTER); + + // Button panel - 添加修改密码按钮 + JPanel buttonPanel = new JPanel(new FlowLayout()); + JButton changePasswordButton = new JButton("修改密码"); + JButton logoutButton = new JButton("退出登录"); + + changePasswordButton.setFont(new Font("微软雅黑", Font.PLAIN, 14)); + logoutButton.setFont(new Font("微软雅黑", Font.PLAIN, 14)); + + buttonPanel.add(changePasswordButton); + buttonPanel.add(logoutButton); + + mainPanel.add(buttonPanel, BorderLayout.SOUTH); + + // Add action listeners + startButton.addActionListener(new StartExamAction()); + changePasswordButton.addActionListener(new ChangePasswordAction()); + logoutButton.addActionListener(e -> NavigationController.showLoginView()); + + add(mainPanel); + } + + private class StartExamAction implements ActionListener { + @Override + public void actionPerformed(ActionEvent e) { + String difficulty = (String) difficultyComboBox.getSelectedItem(); + String countText = countField.getText().trim(); + + try { + int count = Integer.parseInt(countText); + if (count <= 0 || count > 100) { + JOptionPane.showMessageDialog(MainView.this, + "题目数量必须在1-100之间", "错误", JOptionPane.ERROR_MESSAGE); + return; + } + + NavigationController.showExamView(difficulty, count); + } catch (NumberFormatException ex) { + JOptionPane.showMessageDialog(MainView.this, + "请输入有效的数字", "错误", JOptionPane.ERROR_MESSAGE); + } + } + } + + private class ChangePasswordAction implements ActionListener { + @Override + public void actionPerformed(ActionEvent e) { + // 打开修改密码对话框 + new ChangePasswordDialog(MainView.this, currentUser).setVisible(true); + } + } +} \ No newline at end of file diff --git a/src/view/RegisterView.java b/src/view/RegisterView.java new file mode 100644 index 0000000..9f62963 --- /dev/null +++ b/src/view/RegisterView.java @@ -0,0 +1,151 @@ +package view; + +import controller.NavigationController; +import controller.UserController; +import model.User; + +import javax.swing.*; +import java.awt.*; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; + +public class RegisterView extends JFrame { + private JTextField usernameField; // 新增:用户名输入框 + private JTextField emailField; + private JTextField codeField; + private JPasswordField passwordField; + private JPasswordField confirmPasswordField; + private UserController userController; + private String currentUsername; // 保存当前注册的用户名 + + public RegisterView() { + userController = new UserController(); + initializeUI(); + } + + private void initializeUI() { + setTitle("数学学习软件 - 注册"); + setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + setSize(500, 450); // 增加高度以容纳用户名字段 + setLocationRelativeTo(null); + setResizable(false); + + JPanel mainPanel = new JPanel(new BorderLayout(10, 10)); + mainPanel.setBorder(BorderFactory.createEmptyBorder(20, 20, 20, 20)); + + // Title + JLabel titleLabel = new JLabel("用户注册", JLabel.CENTER); + titleLabel.setFont(new Font("微软雅黑", Font.BOLD, 24)); + mainPanel.add(titleLabel, BorderLayout.NORTH); + + // Form panel - 增加用户名字段 + JPanel formPanel = new JPanel(new GridLayout(6, 2, 10, 10)); + + JLabel usernameLabel = new JLabel("用户名:"); + usernameLabel.setFont(new Font("微软雅黑", Font.PLAIN, 14)); + usernameField = new JTextField(); + + JLabel emailLabel = new JLabel("邮箱:"); + emailLabel.setFont(new Font("微软雅黑", Font.PLAIN, 14)); + emailField = new JTextField(); + + JLabel codeLabel = new JLabel("注册码:"); + codeLabel.setFont(new Font("微软雅黑", Font.PLAIN, 14)); + codeField = new JTextField(); + + JLabel passwordLabel = new JLabel("密码:"); + passwordLabel.setFont(new Font("微软雅黑", Font.PLAIN, 14)); + passwordField = new JPasswordField(); + + JLabel confirmPasswordLabel = new JLabel("确认密码:"); + confirmPasswordLabel.setFont(new Font("微软雅黑", Font.PLAIN, 14)); + confirmPasswordField = new JPasswordField(); + + JButton sendCodeButton = new JButton("发送注册码"); + sendCodeButton.setFont(new Font("微软雅黑", Font.PLAIN, 12)); + + JButton registerButton = new JButton("完成注册"); + registerButton.setFont(new Font("微软雅黑", Font.PLAIN, 14)); + + // 布局表单 + formPanel.add(usernameLabel); + formPanel.add(usernameField); + formPanel.add(emailLabel); + formPanel.add(emailField); + formPanel.add(new JLabel()); // Empty cell + formPanel.add(sendCodeButton); + formPanel.add(codeLabel); + formPanel.add(codeField); + formPanel.add(passwordLabel); + formPanel.add(passwordField); + formPanel.add(confirmPasswordLabel); + formPanel.add(confirmPasswordField); + formPanel.add(new JLabel()); // Empty cell + formPanel.add(registerButton); + + mainPanel.add(formPanel, BorderLayout.CENTER); + + // Back button + JButton backButton = new JButton("返回登录"); + backButton.setFont(new Font("微软雅黑", Font.PLAIN, 14)); + backButton.addActionListener(e -> NavigationController.showLoginView()); + + JPanel bottomPanel = new JPanel(new FlowLayout()); + bottomPanel.add(backButton); + mainPanel.add(bottomPanel, BorderLayout.SOUTH); + + // Add action listeners + sendCodeButton.addActionListener(new SendCodeAction()); + registerButton.addActionListener(new RegisterAction()); + + add(mainPanel); + } + + private class SendCodeAction implements ActionListener { + @Override + public void actionPerformed(ActionEvent e) { + String username = usernameField.getText().trim(); + String email = emailField.getText().trim(); + + if (username.isEmpty() || email.isEmpty()) { + JOptionPane.showMessageDialog(RegisterView.this, + "请输入用户名和邮箱", "错误", JOptionPane.ERROR_MESSAGE); + return; + } + + String result = userController.registerUser(username, email); + JOptionPane.showMessageDialog(RegisterView.this, result); + + if (result.contains("发送")) { + currentUsername = username; + } + } + } + + private class RegisterAction implements ActionListener { + @Override + public void actionPerformed(ActionEvent e) { + String username = usernameField.getText().trim(); + String code = codeField.getText().trim(); + String password = new String(passwordField.getPassword()); + String confirmPassword = new String(confirmPasswordField.getPassword()); + + if (username.isEmpty() || code.isEmpty() || password.isEmpty() || confirmPassword.isEmpty()) { + JOptionPane.showMessageDialog(RegisterView.this, + "请填写所有字段", "错误", JOptionPane.ERROR_MESSAGE); + return; + } + + String result = userController.completeRegistration(username, code, password, confirmPassword); + + if (result.equals("注册成功!")) { + JOptionPane.showMessageDialog(RegisterView.this, + result, "成功", JOptionPane.INFORMATION_MESSAGE); + NavigationController.showLoginView(); + } else { + JOptionPane.showMessageDialog(RegisterView.this, + result, "错误", JOptionPane.ERROR_MESSAGE); + } + } + } +} \ No newline at end of file diff --git a/src/view/ResultView.java b/src/view/ResultView.java new file mode 100644 index 0000000..890fa5a --- /dev/null +++ b/src/view/ResultView.java @@ -0,0 +1,69 @@ +package view; + +import controller.NavigationController; + +import javax.swing.*; +import java.awt.*; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; + +public class ResultView extends JFrame { + private JLabel scoreLabel; + private JLabel percentageLabel; + + public ResultView() { + initializeUI(); + } + + private void initializeUI() { + setTitle("数学学习软件 - 成绩界面"); + setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + setSize(400, 300); + setLocationRelativeTo(null); + setResizable(false); + + JPanel mainPanel = new JPanel(new BorderLayout(10, 10)); + mainPanel.setBorder(BorderFactory.createEmptyBorder(20, 20, 20, 20)); + + // Title + JLabel titleLabel = new JLabel("考试结果", JLabel.CENTER); + titleLabel.setFont(new Font("微软雅黑", Font.BOLD, 24)); + mainPanel.add(titleLabel, BorderLayout.NORTH); + + // Result panel + JPanel resultPanel = new JPanel(new GridLayout(2, 1, 10, 10)); + + scoreLabel = new JLabel("", JLabel.CENTER); + scoreLabel.setFont(new Font("微软雅黑", Font.PLAIN, 18)); + + percentageLabel = new JLabel("", JLabel.CENTER); + percentageLabel.setFont(new Font("微软雅黑", Font.PLAIN, 18)); + + resultPanel.add(scoreLabel); + resultPanel.add(percentageLabel); + mainPanel.add(resultPanel, BorderLayout.CENTER); + + // Button panel + JPanel buttonPanel = new JPanel(new FlowLayout()); + JButton continueButton = new JButton("继续做题"); + JButton exitButton = new JButton("退出系统"); + + continueButton.setFont(new Font("微软雅黑", Font.PLAIN, 14)); + exitButton.setFont(new Font("微软雅黑", Font.PLAIN, 14)); + + buttonPanel.add(continueButton); + buttonPanel.add(exitButton); + mainPanel.add(buttonPanel, BorderLayout.SOUTH); + + // Add action listeners + continueButton.addActionListener(e -> NavigationController.showMainView()); + exitButton.addActionListener(e -> System.exit(0)); + + add(mainPanel); + } + + public void setResults(int score, int total, double percentage) { + scoreLabel.setText(String.format("得分: %d / %d", score, total)); + percentageLabel.setText(String.format("正确率: %.1f%%", percentage)); + } +} \ No newline at end of file