diff --git a/pom.xml b/pom.xml index 70e9913..1c15ac9 100644 --- a/pom.xml +++ b/pom.xml @@ -74,7 +74,7 @@ javafx-maven-plugin ${javafx.maven.plugin.version} - com.personalproject.ui.MathExamGUI + com.personalproject.ui.MathExamGui @@ -86,7 +86,7 @@ default-cli - com.personalproject.ui.MathExamGUI + com.personalproject.ui.MathExamGui @@ -107,7 +107,7 @@ - com.personalproject.ui.MathExamGUI + com.personalproject.ui.MathExamGui @@ -127,7 +127,7 @@ - com.personalproject.ui.MathExamGUI + com.personalproject.ui.MathExamGui diff --git a/src/main/java/com/personalproject/MathExamApplication.java b/src/main/java/com/personalproject/MathExamApplication.java index f8fa725..3298df1 100644 --- a/src/main/java/com/personalproject/MathExamApplication.java +++ b/src/main/java/com/personalproject/MathExamApplication.java @@ -1,10 +1,9 @@ package com.personalproject; -import com.personalproject.ui.MathExamGUI; +import com.personalproject.ui.MathExamGui; /** - * 数学学习软件主应用程序入口. - * 这个类现在启动JavaFX GUI应用程序。 + * 数学学习软件主应用程序入口. 这个类现在启动JavaFX GUI应用程序. */ public final class MathExamApplication { @@ -15,6 +14,6 @@ public final class MathExamApplication { */ public static void main(String[] args) { // 启动JavaFX应用程序 - MathExamGUI.main(args); + MathExamGui.main(args); } -} \ No newline at end of file +} diff --git a/src/main/java/com/personalproject/auth/AccountRepository.java b/src/main/java/com/personalproject/auth/AccountRepository.java index 2a2f665..e30df5b 100644 --- a/src/main/java/com/personalproject/auth/AccountRepository.java +++ b/src/main/java/com/personalproject/auth/AccountRepository.java @@ -26,6 +26,9 @@ public final class AccountRepository { private final Map accounts = new ConcurrentHashMap<>(); + /** + * 创建账号仓库并立即加载磁盘中的账号数据. + */ public AccountRepository() { loadAccounts(); } @@ -54,7 +57,7 @@ public final class AccountRepository { } /** - * 使用电子邮箱注册新用户账号。 + * 使用电子邮箱注册新用户账号. * * @param username 用户名 * @param email 邮箱地址 @@ -82,7 +85,8 @@ public final class AccountRepository { return false; } - LocalDateTime registrationDate = existing != null ? existing.registrationDate() : LocalDateTime.now(); + LocalDateTime registrationDate = + existing != null ? existing.registrationDate() : LocalDateTime.now(); UserAccount account = new UserAccount( normalizedUsername, normalizedEmail, @@ -97,7 +101,7 @@ public final class AccountRepository { } /** - * 在注册后为用户设置密码。 + * 在注册后为用户设置密码. * * @param username 用户名 * @param password 要设置的密码 @@ -126,7 +130,7 @@ public final class AccountRepository { } /** - * 修改现有用户的密码。 + * 修改现有用户的密码. * * @param username 用户名 * @param oldPassword 当前密码 @@ -161,7 +165,7 @@ public final class AccountRepository { } /** - * 移除未完成注册的用户,便于重新注册。 + * 移除未完成注册的用户,便于重新注册. * * @param username 待移除的用户名 */ @@ -178,7 +182,7 @@ public final class AccountRepository { } /** - * 检查用户是否存在。 + * 检查用户是否存在. * * @param username 待检查的用户名 * @return 若存在则返回 true,否则返回 false @@ -191,7 +195,7 @@ public final class AccountRepository { } /** - * 按用户名获取用户账户。 + * 按用户名获取用户账户. * * @param username 用户名 * @return 若找到则返回包含用户账户的 Optional diff --git a/src/main/java/com/personalproject/auth/EmailService.java b/src/main/java/com/personalproject/auth/EmailService.java index 4d357bf..f12a81d 100644 --- a/src/main/java/com/personalproject/auth/EmailService.java +++ b/src/main/java/com/personalproject/auth/EmailService.java @@ -26,7 +26,7 @@ import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.atomic.AtomicReference; /** - * 用于发送带有注册码的电子邮件的工具类。 + * 用于发送带有注册码的电子邮件的工具类. */ public final class EmailService { @@ -46,7 +46,7 @@ public final class EmailService { } /** - * 生成随机注册码。 + * 生成随机注册码. * * @return 随机生成的注册码 */ @@ -59,7 +59,7 @@ public final class EmailService { } /** - * 将注册码发送到指定邮箱。 + * 将注册码发送到指定邮箱. * * @param email 收件人邮箱 * @param registrationCode 要发送的注册码 @@ -79,7 +79,7 @@ public final class EmailService { } /** - * 获取最近一次发送到指定邮箱的验证码(便于调试或测试)。 + * 获取最近一次发送到指定邮箱的验证码(便于调试或测试). * * @param email 收件人邮箱 * @return 若存在则返回验证码 @@ -92,7 +92,7 @@ public final class EmailService { } /** - * 校验电子邮件地址的格式是否有效。 + * 校验电子邮件地址的格式是否有效. * * @param email 待校验的邮箱地址 * @return 若格式有效则返回 true,否则返回 false @@ -134,9 +134,9 @@ public final class EmailService { } String username = require(properties, "mail.username"); - String password = require(properties, "mail.password"); - String from = properties.getProperty("mail.from", username); - String subject = properties.getProperty("mail.subject", DEFAULT_SUBJECT); + final String password = require(properties, "mail.password"); + final String from = properties.getProperty("mail.from", username); + final String subject = properties.getProperty("mail.subject", DEFAULT_SUBJECT); Properties smtpProperties = new Properties(); for (Map.Entry entry : properties.entrySet()) { @@ -194,7 +194,7 @@ public final class EmailService { String sanitizedEmail = sanitizeEmail(email); String timestamp = DATE_TIME_FORMATTER.format(LocalDateTime.now()); - Path messageFile = OUTBOX_DIRECTORY.resolve(sanitizedEmail + "_" + timestamp + ".txt"); + final Path messageFile = OUTBOX_DIRECTORY.resolve(sanitizedEmail + "_" + timestamp + ".txt"); StringBuilder content = new StringBuilder(); content.append("收件人: ").append(email).append(System.lineSeparator()); content.append("注册码: ").append(registrationCode).append(System.lineSeparator()); @@ -226,5 +226,6 @@ public final class EmailService { String password, String from, String subject) { + } } diff --git a/src/main/java/com/personalproject/auth/PasswordValidator.java b/src/main/java/com/personalproject/auth/PasswordValidator.java index 53740d8..e8196af 100644 --- a/src/main/java/com/personalproject/auth/PasswordValidator.java +++ b/src/main/java/com/personalproject/auth/PasswordValidator.java @@ -3,7 +3,7 @@ package com.personalproject.auth; import java.util.regex.Pattern; /** - * 用于验证密码规则的工具类。 + * 用于验证密码规则的工具类. */ public final class PasswordValidator { @@ -15,7 +15,7 @@ public final class PasswordValidator { } /** - * 校验密码是否满足以下要求: + * 校验密码是否满足以下要求. * - 长度 6-10 位 * - 至少包含一个大写字母 * - 至少包含一个小写字母 diff --git a/src/main/java/com/personalproject/auth/UserAccount.java b/src/main/java/com/personalproject/auth/UserAccount.java index 07543a0..3900693 100644 --- a/src/main/java/com/personalproject/auth/UserAccount.java +++ b/src/main/java/com/personalproject/auth/UserAccount.java @@ -15,7 +15,7 @@ public record UserAccount( boolean isRegistered) { /** - * 创建新的用户账户,并使用当前时间作为注册时间。 + * 创建新的用户账户,并使用当前时间作为注册时间. * * @param username 用户名 * @param email 邮箱地址 diff --git a/src/main/java/com/personalproject/controller/MathLearningController.java b/src/main/java/com/personalproject/controller/MathLearningController.java index 4edd694..0a5fe61 100644 --- a/src/main/java/com/personalproject/controller/MathLearningController.java +++ b/src/main/java/com/personalproject/controller/MathLearningController.java @@ -144,7 +144,7 @@ public final class MathLearningController { } /** - * 按用户名获取用户账户。 + * 按用户名获取用户账户. * * @param username 用户名 * @return 若找到则返回包含用户账户的 Optional diff --git a/src/main/java/com/personalproject/generator/PrimaryQuestionGenerator.java b/src/main/java/com/personalproject/generator/PrimaryQuestionGenerator.java index 8041330..6c1536b 100644 --- a/src/main/java/com/personalproject/generator/PrimaryQuestionGenerator.java +++ b/src/main/java/com/personalproject/generator/PrimaryQuestionGenerator.java @@ -2,7 +2,6 @@ package com.personalproject.generator; import com.personalproject.model.QuizQuestion; import com.personalproject.service.MathExpressionEvaluator; - import java.util.ArrayList; import java.util.Collections; import java.util.LinkedHashSet; @@ -78,7 +77,7 @@ public final class PrimaryQuestionGenerator implements QuestionGenerator, QuizQu } /** - * 生成选择题选项 + * 生成选择题选项. */ private List generateOptions(double correctAnswer, Random random) { String correctOption = formatOption(correctAnswer); diff --git a/src/main/java/com/personalproject/model/ExamSession.java b/src/main/java/com/personalproject/model/ExamSession.java index a57a808..bce8b58 100644 --- a/src/main/java/com/personalproject/model/ExamSession.java +++ b/src/main/java/com/personalproject/model/ExamSession.java @@ -6,7 +6,7 @@ import java.util.Collections; import java.util.List; /** - * 表示用户的考试会话。 + * 表示用户的考试会话. */ public final class ExamSession { @@ -18,7 +18,7 @@ public final class ExamSession { private int currentQuestionIndex; /** - * 创建新的考试会话。 + * 创建新的考试会话. * * @param username 考生的用户名 * @param difficultyLevel 考试的难度级别 @@ -45,7 +45,7 @@ public final class ExamSession { } /** - * 获取考生的用户名。 + * 获取考生的用户名. * * @return 用户名 */ @@ -54,7 +54,7 @@ public final class ExamSession { } /** - * 获取考试的难度级别。 + * 获取考试的难度级别. * * @return 考试难度级别 */ @@ -63,7 +63,7 @@ public final class ExamSession { } /** - * 获取考试中的题目列表。 + * 获取考试中的题目列表. * * @return 不可修改的题目列表 */ @@ -72,7 +72,7 @@ public final class ExamSession { } /** - * 获取用户对各题的作答。 + * 获取用户对各题的作答. * * @return 答案索引列表(-1 表示未选择) */ @@ -81,7 +81,7 @@ public final class ExamSession { } /** - * 获取当前题目的索引。 + * 获取当前题目的索引. * * @return 当前题目索引 */ @@ -90,7 +90,7 @@ public final class ExamSession { } /** - * 为当前题目记录用户的答案。 + * 为当前题目记录用户的答案. * * @param answerIndex 选中答案的索引 */ @@ -106,7 +106,7 @@ public final class ExamSession { } /** - * 跳转到下一题。 + * 跳转到下一题. * * @return 若成功跳转则返回 true,若已是最后一题则返回 false */ @@ -119,7 +119,7 @@ public final class ExamSession { } /** - * 返回上一题。 + * 返回上一题. * * @return 若成功返回则返回 true,若已是第一题则返回 false */ @@ -132,7 +132,7 @@ public final class ExamSession { } /** - * 检查考试是否完成(所有题目已作答或到达最后一题)。 + * 检查考试是否完成(所有题目已作答或到达最后一题). * * @return 若考试已完成则返回 true,否则返回 false */ @@ -141,7 +141,7 @@ public final class ExamSession { } /** - * 获取当前题目。 + * 获取当前题目. * * @return 当前的测验题 */ @@ -153,7 +153,7 @@ public final class ExamSession { } /** - * 获取指定题目的用户答案。 + * 获取指定题目的用户答案. * * @param questionIndex 题目索引 * @return 用户答案的索引(未选择时为 -1) @@ -166,7 +166,7 @@ public final class ExamSession { } /** - * 计算得分百分比。 + * 计算得分百分比. * * @return 0-100 范围内的得分百分比 */ @@ -183,7 +183,7 @@ public final class ExamSession { } /** - * 获取考试中的题目总数。 + * 获取考试中的题目总数. * * @return 题目总数 */ @@ -192,7 +192,7 @@ public final class ExamSession { } /** - * 检查指定题目是否已作答。 + * 检查指定题目是否已作答. * * @param questionIndex 题目索引 * @return 若已作答则返回 true,否则返回 false @@ -205,7 +205,7 @@ public final class ExamSession { } /** - * 获取考试开始时间。 + * 获取考试开始时间. * * @return 开始时间 */ @@ -214,7 +214,7 @@ public final class ExamSession { } /** - * 获取答对的题目数量。 + * 获取答对的题目数量. * * @return 正确题目数量 */ @@ -231,14 +231,14 @@ public final class ExamSession { } /** - * 获取答错的题目数量。 + * 获取答错的题目数量. * * @return 错误题目数量 */ public int getIncorrectAnswersCount() { int totalAnswered = 0; int correctCount = 0; - + for (int i = 0; i < questions.size(); i++) { int userAnswer = userAnswers.get(i); if (userAnswer != -1) { @@ -249,7 +249,7 @@ public final class ExamSession { } } } - + return totalAnswered - correctCount; } } diff --git a/src/main/java/com/personalproject/model/QuizQuestion.java b/src/main/java/com/personalproject/model/QuizQuestion.java index 52c8f6b..cb6c8c9 100644 --- a/src/main/java/com/personalproject/model/QuizQuestion.java +++ b/src/main/java/com/personalproject/model/QuizQuestion.java @@ -3,7 +3,7 @@ package com.personalproject.model; import java.util.List; /** - * 表示一个带有多项选择的测验题目。 + * 表示一个带有多项选择的测验题目. */ public final class QuizQuestion { @@ -12,7 +12,7 @@ public final class QuizQuestion { private final int correctAnswerIndex; /** - * 创建新的测验题目。 + * 创建新的测验题目. * * @param questionText 题目文本 * @param options 答案选项列表 @@ -35,7 +35,7 @@ public final class QuizQuestion { } /** - * 获取题目文本。 + * 获取题目文本. * * @return 题目文本 */ @@ -44,7 +44,7 @@ public final class QuizQuestion { } /** - * 获取答案选项列表。 + * 获取答案选项列表. * * @return 不可修改的答案选项列表 */ @@ -53,7 +53,7 @@ public final class QuizQuestion { } /** - * 获取正确答案在选项列表中的索引。 + * 获取正确答案在选项列表中的索引. * * @return 正确答案的索引 */ @@ -62,7 +62,7 @@ public final class QuizQuestion { } /** - * 检查给定的答案索引是否正确。 + * 检查给定的答案索引是否正确. * * @param answerIndex 用户答案的索引 * @return 若答案正确则返回 true,否则返回 false diff --git a/src/main/java/com/personalproject/service/ExamService.java b/src/main/java/com/personalproject/service/ExamService.java index f72dcd7..643c311 100644 --- a/src/main/java/com/personalproject/service/ExamService.java +++ b/src/main/java/com/personalproject/service/ExamService.java @@ -31,7 +31,7 @@ public final class ExamService { * * @param generatorMap 难度级别到题目生成器的映射 * @param questionGenerationService 题目生成服务 - * @param questionStorageService 题目存储服务 + * @param questionStorageService 题目存储服务 */ public ExamService( Map generatorMap, diff --git a/src/main/java/com/personalproject/service/MathExpressionEvaluator.java b/src/main/java/com/personalproject/service/MathExpressionEvaluator.java index ff77f94..49b919d 100644 --- a/src/main/java/com/personalproject/service/MathExpressionEvaluator.java +++ b/src/main/java/com/personalproject/service/MathExpressionEvaluator.java @@ -7,7 +7,7 @@ import java.util.function.DoubleUnaryOperator; import java.util.regex.Pattern; /** - * 可处理基本算术运算的数学表达式求值器。 + * 可处理基本算术运算的数学表达式求值器. */ public final class MathExpressionEvaluator { @@ -33,7 +33,7 @@ public final class MathExpressionEvaluator { } /** - * 计算数学表达式字符串的结果。 + * 计算数学表达式字符串的结果. * * @param expression 要计算的数学表达式 * @return 计算结果 @@ -60,7 +60,7 @@ public final class MathExpressionEvaluator { } /** - * 将表达式拆分为数字与运算符的记号。 + * 将表达式拆分为数字与运算符的记号. * * @param expression 待拆分的表达式 * @return 记号数组 @@ -120,7 +120,7 @@ public final class MathExpressionEvaluator { } /** - * 检查字符是否为运算符。 + * 检查字符是否为运算符. * * @param c 待检查的字符 * @return 若字符是运算符则返回 true,否则返回 false @@ -134,7 +134,7 @@ public final class MathExpressionEvaluator { } /** - * 使用调度场算法将中缀表达式转换为后缀表达式。 + * 使用调度场算法将中缀表达式转换为后缀表达式. * * @param tokens 中缀表达式的记号数组 * @return 后缀表达式的记号数组 @@ -182,7 +182,7 @@ public final class MathExpressionEvaluator { } /** - * 计算后缀表达式的值。 + * 计算后缀表达式的值. * * @param postfix 后缀表达式的记号数组 * @return 计算结果 @@ -204,7 +204,8 @@ public final class MathExpressionEvaluator { values.push(result); } else if (isFunction(token)) { if (values.isEmpty()) { - throw new IllegalArgumentException("Invalid expression: insufficient operands for function"); + throw new IllegalArgumentException( + "Invalid expression: insufficient operands for function"); } double value = values.pop(); values.push(applyFunction(token, value)); @@ -221,7 +222,7 @@ public final class MathExpressionEvaluator { } /** - * 对两个操作数执行指定运算。 + * 对两个操作数执行指定运算. * * @param a 第一个操作数 * @param b 第二个操作数 @@ -257,7 +258,7 @@ public final class MathExpressionEvaluator { } /** - * 检查记号是否为数字。 + * 检查记号是否为数字. * * @param token 待检查的记号 * @return 若为数字则返回 true,否则返回 false diff --git a/src/main/java/com/personalproject/service/MathLearningService.java b/src/main/java/com/personalproject/service/MathLearningService.java index 768d98e..71a0fd8 100644 --- a/src/main/java/com/personalproject/service/MathLearningService.java +++ b/src/main/java/com/personalproject/service/MathLearningService.java @@ -169,7 +169,7 @@ public final class MathLearningService { } /** - * 按用户名获取用户账户。 + * 按用户名获取用户账户. * * @param username 用户名 * @return 若找到则返回包含用户账户的 Optional diff --git a/src/main/java/com/personalproject/service/RegistrationService.java b/src/main/java/com/personalproject/service/RegistrationService.java index 099152c..ee2bc82 100644 --- a/src/main/java/com/personalproject/service/RegistrationService.java +++ b/src/main/java/com/personalproject/service/RegistrationService.java @@ -187,7 +187,7 @@ public final class RegistrationService { } /** - * 按用户名获取用户账户。 + * 按用户名获取用户账户. * * @param username 用户名 * @return 若找到则返回包含用户账户的 Optional diff --git a/src/main/java/com/personalproject/ui/MathExamGUI.java b/src/main/java/com/personalproject/ui/MathExamGui.java similarity index 87% rename from src/main/java/com/personalproject/ui/MathExamGUI.java rename to src/main/java/com/personalproject/ui/MathExamGui.java index 272bf36..2603eaf 100644 --- a/src/main/java/com/personalproject/ui/MathExamGUI.java +++ b/src/main/java/com/personalproject/ui/MathExamGui.java @@ -1,8 +1,5 @@ package com.personalproject.ui; -import javafx.application.Application; -import javafx.scene.Scene; -import javafx.stage.Stage; import com.personalproject.controller.MathLearningController; import com.personalproject.generator.HighSchoolQuestionGenerator; import com.personalproject.generator.MiddleSchoolQuestionGenerator; @@ -11,15 +8,16 @@ import com.personalproject.generator.QuestionGenerator; import com.personalproject.model.DifficultyLevel; import com.personalproject.service.QuestionGenerationService; import com.personalproject.ui.scenes.LoginScene; - import java.util.EnumMap; import java.util.Map; +import javafx.application.Application; +import javafx.scene.Scene; +import javafx.stage.Stage; /** - * 数学学习软件的 JavaFX 图形界面应用程序。 - * 这是图形界面的主要入口点。 + * 数学学习软件的 JavaFX 图形界面应用程序. 这是图形界面的主要入口点. */ -public final class MathExamGUI extends Application { +public final class MathExamGui extends Application { private MathLearningController controller; @@ -30,22 +28,23 @@ public final class MathExamGUI extends Application { generatorMap.put(DifficultyLevel.PRIMARY, new PrimaryQuestionGenerator()); generatorMap.put(DifficultyLevel.MIDDLE, new MiddleSchoolQuestionGenerator()); generatorMap.put(DifficultyLevel.HIGH, new HighSchoolQuestionGenerator()); - QuestionGenerationService questionGenerationService = new QuestionGenerationService(generatorMap); + QuestionGenerationService questionGenerationService = new QuestionGenerationService( + generatorMap); this.controller = new MathLearningController(generatorMap, questionGenerationService); // 配置主舞台 primaryStage.setTitle("数学学习软件"); - + // 从登录界面开始 LoginScene loginScene = new LoginScene(primaryStage, controller); Scene scene = new Scene(loginScene, 600, 400); - + primaryStage.setScene(scene); primaryStage.show(); } /** - * 启动 JavaFX 应用程序。 + * 启动 JavaFX 应用程序. * * @param args 命令行参数 */ diff --git a/src/main/java/com/personalproject/ui/scenes/LoginScene.java b/src/main/java/com/personalproject/ui/scenes/LoginScene.java index 4d4d6be..b12f741 100644 --- a/src/main/java/com/personalproject/ui/scenes/LoginScene.java +++ b/src/main/java/com/personalproject/ui/scenes/LoginScene.java @@ -1,18 +1,24 @@ package com.personalproject.ui.scenes; +import com.personalproject.controller.MathLearningController; +import com.personalproject.ui.views.MainMenuView; import javafx.geometry.Insets; import javafx.geometry.Pos; -import javafx.scene.control.*; -import javafx.scene.layout.*; +import javafx.scene.control.Alert; +import javafx.scene.control.Button; +import javafx.scene.control.Label; +import javafx.scene.control.PasswordField; +import javafx.scene.control.TextField; +import javafx.scene.layout.BorderPane; +import javafx.scene.layout.GridPane; +import javafx.scene.layout.HBox; +import javafx.scene.layout.VBox; import javafx.scene.text.Font; import javafx.scene.text.FontWeight; import javafx.stage.Stage; -import com.personalproject.controller.MathLearningController; -import com.personalproject.ui.views.MainMenuView; -import com.personalproject.ui.scenes.RegistrationScene; /** - * 负责处理用户登录与注册的场景。 + * 负责处理用户登录与注册的场景. */ public class LoginScene extends BorderPane { @@ -24,79 +30,79 @@ public class LoginScene extends BorderPane { private Button registerButton; /** - * LoginScene 的构造函数。 + * LoginScene 的构造函数. * * @param primaryStage 应用程序的主舞台 - * @param controller 数学学习控制器 + * @param controller 数学学习控制器 */ public LoginScene(Stage primaryStage, MathLearningController controller) { this.primaryStage = primaryStage; this.controller = controller; - initializeUI(); + initializeUi(); } /** - * 初始化界面组件。 + * 初始化界面组件. */ - private void initializeUI() { + private void initializeUi() { // 创建主布局 VBox mainLayout = new VBox(15); mainLayout.setAlignment(Pos.CENTER); mainLayout.setPadding(new Insets(20)); - + // 标题 - Label titleLabel = new Label("数学学习软件"); + final Label titleLabel = new Label("数学学习软件"); titleLabel.setFont(Font.font("System", FontWeight.BOLD, 24)); - + // 登录表单 GridPane loginForm = new GridPane(); loginForm.setHgap(10); loginForm.setVgap(10); loginForm.setAlignment(Pos.CENTER); - - Label usernameLabel = new Label("用户名:"); + + final Label usernameLabel = new Label("用户名:"); usernameField = new TextField(); usernameField.setPrefWidth(200); - - Label passwordLabel = new Label("密码:"); + + final Label passwordLabel = new Label("密码:"); passwordField = new PasswordField(); passwordField.setPrefWidth(200); - + loginForm.add(usernameLabel, 0, 0); loginForm.add(usernameField, 1, 0); loginForm.add(passwordLabel, 0, 1); loginForm.add(passwordField, 1, 1); - + // 按钮 HBox buttonBox = new HBox(10); buttonBox.setAlignment(Pos.CENTER); - + loginButton = new Button("登录"); registerButton = new Button("注册"); - + // 设置按钮样式 loginButton.setPrefWidth(100); registerButton.setPrefWidth(100); - + buttonBox.getChildren().addAll(loginButton, registerButton); - + // 将组件添加到主布局 mainLayout.getChildren().addAll(titleLabel, loginForm, buttonBox); - + // 将主布局放到边界面板中央 setCenter(mainLayout); - + // 添加事件处理器 addEventHandlers(); } /** - * 为界面组件添加事件处理器。 + * 为界面组件添加事件处理器. */ private void addEventHandlers() { loginButton.setOnAction(e -> handleLogin()); registerButton.setOnAction(e -> handleRegistration()); - + // 允许使用回车键登录 setOnKeyPressed(event -> { if (event.getCode().toString().equals("ENTER")) { @@ -106,7 +112,7 @@ public class LoginScene extends BorderPane { } /** - * 处理登录流程。 + * 处理登录流程. */ private void handleLogin() { String username = usernameField.getText().trim(); @@ -131,7 +137,7 @@ public class LoginScene extends BorderPane { } /** - * 处理注册流程。 + * 处理注册流程. */ private void handleRegistration() { // 切换到注册界面 @@ -140,11 +146,11 @@ public class LoginScene extends BorderPane { } /** - * 显示提示对话框。 + * 显示提示对话框. * * @param alertType 提示类型 - * @param title 对话框标题 - * @param message 显示的消息 + * @param title 对话框标题 + * @param message 显示的消息 */ private void showAlert(Alert.AlertType alertType, String title, String message) { Alert alert = new Alert(alertType); diff --git a/src/main/java/com/personalproject/ui/scenes/RegistrationScene.java b/src/main/java/com/personalproject/ui/scenes/RegistrationScene.java index c180c73..2d63930 100644 --- a/src/main/java/com/personalproject/ui/scenes/RegistrationScene.java +++ b/src/main/java/com/personalproject/ui/scenes/RegistrationScene.java @@ -1,18 +1,25 @@ package com.personalproject.ui.scenes; +import com.personalproject.controller.MathLearningController; +import com.personalproject.model.DifficultyLevel; +import com.personalproject.ui.views.MainMenuView; import javafx.geometry.Insets; import javafx.geometry.Pos; -import javafx.scene.control.*; -import javafx.scene.layout.*; +import javafx.scene.control.Alert; +import javafx.scene.control.Button; +import javafx.scene.control.ComboBox; +import javafx.scene.control.Label; +import javafx.scene.control.PasswordField; +import javafx.scene.control.TextField; +import javafx.scene.layout.BorderPane; +import javafx.scene.layout.GridPane; +import javafx.scene.layout.VBox; import javafx.scene.text.Font; import javafx.scene.text.FontWeight; import javafx.stage.Stage; -import com.personalproject.controller.MathLearningController; -import com.personalproject.model.DifficultyLevel; -import com.personalproject.ui.scenes.LoginScene; /** - * 负责处理用户注册的场景。 + * 负责处理用户注册的场景. */ public class RegistrationScene extends BorderPane { @@ -31,120 +38,121 @@ public class RegistrationScene extends BorderPane { private VBox registrationForm; /** - * RegistrationScene 的构造函数。 + * RegistrationScene 的构造函数. * * @param primaryStage 应用程序的主舞台 - * @param controller 数学学习控制器 + * @param controller 数学学习控制器 */ public RegistrationScene(Stage primaryStage, MathLearningController controller) { this.primaryStage = primaryStage; this.controller = controller; - initializeUI(); + initializeUi(); } /** - * 初始化界面组件。 + * 初始化界面组件. */ - private void initializeUI() { + private void initializeUi() { // 创建主布局 VBox mainLayout = new VBox(15); mainLayout.setAlignment(Pos.CENTER); mainLayout.setPadding(new Insets(20)); - + // 标题 - Label titleLabel = new Label("用户注册"); + final Label titleLabel = new Label("用户注册"); titleLabel.setFont(Font.font("System", FontWeight.BOLD, 24)); - + // 注册表单 registrationForm = new VBox(15); registrationForm.setAlignment(Pos.CENTER); - + // 步骤1:填写基础信息 GridPane basicInfoForm = new GridPane(); basicInfoForm.setHgap(10); basicInfoForm.setVgap(10); basicInfoForm.setAlignment(Pos.CENTER); - - Label usernameLabel = new Label("用户名:"); + + final Label usernameLabel = new Label("用户名:"); usernameField = new TextField(); usernameField.setPrefWidth(200); - - Label emailLabel = new Label("邮箱:"); + + final Label emailLabel = new Label("邮箱:"); emailField = new TextField(); emailField.setPrefWidth(200); - - Label difficultyLabel = new Label("默认难度:"); + + final Label difficultyLabel = new Label("默认难度:"); difficultyComboBox = new ComboBox<>(); - difficultyComboBox.getItems().addAll(DifficultyLevel.PRIMARY, DifficultyLevel.MIDDLE, DifficultyLevel.HIGH); + difficultyComboBox.getItems() + .addAll(DifficultyLevel.PRIMARY, DifficultyLevel.MIDDLE, DifficultyLevel.HIGH); difficultyComboBox.setValue(DifficultyLevel.PRIMARY); difficultyComboBox.setPrefWidth(200); - + basicInfoForm.add(usernameLabel, 0, 0); basicInfoForm.add(usernameField, 1, 0); basicInfoForm.add(emailLabel, 0, 1); basicInfoForm.add(emailField, 1, 1); basicInfoForm.add(difficultyLabel, 0, 2); basicInfoForm.add(difficultyComboBox, 1, 2); - + sendCodeButton = new Button("发送注册码"); sendCodeButton.setPrefWidth(120); - + registrationForm.getChildren().addAll(basicInfoForm, sendCodeButton); - + // 步骤2:验证码验证(初始隐藏) VBox verificationSection = new VBox(10); verificationSection.setAlignment(Pos.CENTER); verificationSection.setVisible(false); verificationSection.setManaged(false); - - Label codeLabel = new Label("注册码:"); + + final Label codeLabel = new Label("注册码:"); registrationCodeField = new TextField(); registrationCodeField.setPrefWidth(200); - + verifyCodeButton = new Button("验证注册码"); verifyCodeButton.setPrefWidth(120); - + verificationSection.getChildren().addAll(codeLabel, registrationCodeField, verifyCodeButton); registrationForm.getChildren().add(verificationSection); - + // 步骤3:设置密码(初始隐藏) VBox passwordSection = new VBox(10); passwordSection.setAlignment(Pos.CENTER); passwordSection.setVisible(false); passwordSection.setManaged(false); - - Label passwordLabel = new Label("设置密码 (6-10位,包含大小写字母和数字):"); + + final Label passwordLabel = new Label("设置密码 (6-10位,包含大小写字母和数字):"); passwordField = new PasswordField(); passwordField.setPrefWidth(200); - - Label confirmPasswordLabel = new Label("确认密码:"); + + final Label confirmPasswordLabel = new Label("确认密码:"); confirmPasswordField = new PasswordField(); confirmPasswordField.setPrefWidth(200); - + setPasswordButton = new Button("设置密码"); setPasswordButton.setPrefWidth(120); - - passwordSection.getChildren().addAll(passwordLabel, passwordField, confirmPasswordLabel, + + passwordSection.getChildren().addAll(passwordLabel, passwordField, confirmPasswordLabel, confirmPasswordField, setPasswordButton); registrationForm.getChildren().add(passwordSection); - + // 返回按钮 backButton = new Button("返回"); backButton.setPrefWidth(100); - + // 将组件添加到主布局 mainLayout.getChildren().addAll(titleLabel, registrationForm, backButton); - + setCenter(mainLayout); - + // 添加事件处理器 addEventHandlers(sendCodeButton, verificationSection, verifyCodeButton, passwordSection); } /** - * 为界面组件添加事件处理器。 + * 为界面组件添加事件处理器. */ - private void addEventHandlers(Button sendCodeButton, VBox verificationSection, + private void addEventHandlers(Button sendCodeButton, VBox verificationSection, Button verifyCodeButton, VBox passwordSection) { sendCodeButton.setOnAction(e -> handleSendCode(verificationSection)); verifyCodeButton.setOnAction(e -> handleVerifyCode(passwordSection)); @@ -153,12 +161,12 @@ public class RegistrationScene extends BorderPane { } /** - * 处理发送注册码的逻辑。 + * 处理发送注册码的逻辑. */ private void handleSendCode(VBox verificationSection) { - String username = usernameField.getText().trim(); - String email = emailField.getText().trim(); - DifficultyLevel difficultyLevel = difficultyComboBox.getValue(); + final String username = usernameField.getText().trim(); + final String email = emailField.getText().trim(); + final DifficultyLevel difficultyLevel = difficultyComboBox.getValue(); if (username.isEmpty() || email.isEmpty()) { showAlert(Alert.AlertType.WARNING, "警告", "请输入用户名和邮箱"); @@ -183,11 +191,11 @@ public class RegistrationScene extends BorderPane { } /** - * 处理注册码验证。 + * 处理注册码验证. */ private void handleVerifyCode(VBox passwordSection) { - String username = usernameField.getText().trim(); - String registrationCode = registrationCodeField.getText().trim(); + final String username = usernameField.getText().trim(); + final String registrationCode = registrationCodeField.getText().trim(); if (registrationCode.isEmpty()) { showAlert(Alert.AlertType.WARNING, "警告", "请输入注册码"); @@ -206,12 +214,12 @@ public class RegistrationScene extends BorderPane { } /** - * 处理设置用户密码的逻辑。 + * 处理设置用户密码的逻辑. */ private void handleSetPassword() { - String username = usernameField.getText().trim(); - String password = passwordField.getText(); - String confirmPassword = confirmPasswordField.getText(); + final String username = usernameField.getText().trim(); + final String password = passwordField.getText(); + final String confirmPassword = confirmPasswordField.getText(); if (password.isEmpty() || confirmPassword.isEmpty()) { showAlert(Alert.AlertType.WARNING, "警告", "请输入并确认密码"); @@ -224,7 +232,7 @@ public class RegistrationScene extends BorderPane { } if (!controller.isValidPassword(password)) { - showAlert(Alert.AlertType.ERROR, "密码不符合要求", + showAlert(Alert.AlertType.ERROR, "密码不符合要求", "密码长度必须为6-10位,且包含大小写字母和数字"); return; } @@ -232,15 +240,26 @@ public class RegistrationScene extends BorderPane { boolean success = controller.setPassword(username, password); if (success) { - showAlert(Alert.AlertType.INFORMATION, "注册成功", "注册成功!请登录。"); - handleBack(); // 返回登录界面 + var userAccountOptional = controller.getUserAccount(username); + if (userAccountOptional.isPresent()) { + showAlert(Alert.AlertType.INFORMATION, "注册成功", "注册成功!正在进入难度选择界面。"); + MainMenuView mainMenuView = new MainMenuView(primaryStage, controller, + userAccountOptional.get()); + if (primaryStage.getScene() != null) { + primaryStage.getScene().setRoot(mainMenuView); + } + } else { + showAlert(Alert.AlertType.WARNING, "注册提示", + "注册成功,但未能加载用户信息,请使用新密码登录。"); + handleBack(); + } } else { showAlert(Alert.AlertType.ERROR, "设置密码失败", "设置密码失败,请重试。"); } } /** - * 处理返回按钮的操作。 + * 处理返回按钮的操作. */ private void handleBack() { LoginScene loginScene = new LoginScene(primaryStage, controller); @@ -248,11 +267,11 @@ public class RegistrationScene extends BorderPane { } /** - * 显示提示对话框。 + * 显示提示对话框. * * @param alertType 提示类型 - * @param title 对话框标题 - * @param message 显示的消息 + * @param title 对话框标题 + * @param message 显示的消息 */ private void showAlert(Alert.AlertType alertType, String title, String message) { Alert alert = new Alert(alertType); diff --git a/src/main/java/com/personalproject/ui/views/ExamResultsView.java b/src/main/java/com/personalproject/ui/views/ExamResultsView.java index 64d0e91..18de3c2 100644 --- a/src/main/java/com/personalproject/ui/views/ExamResultsView.java +++ b/src/main/java/com/personalproject/ui/views/ExamResultsView.java @@ -1,19 +1,21 @@ package com.personalproject.ui.views; +import com.personalproject.controller.MathLearningController; +import com.personalproject.model.ExamSession; import javafx.geometry.Insets; import javafx.geometry.Pos; -import javafx.scene.control.*; -import javafx.scene.layout.*; +import javafx.scene.control.Alert; +import javafx.scene.control.Button; +import javafx.scene.control.Label; +import javafx.scene.layout.BorderPane; +import javafx.scene.layout.HBox; +import javafx.scene.layout.VBox; import javafx.scene.text.Font; import javafx.scene.text.FontWeight; import javafx.stage.Stage; -import com.personalproject.controller.MathLearningController; -import com.personalproject.model.ExamSession; -import com.personalproject.auth.UserAccount; -import com.personalproject.ui.views.MainMenuView; /** - * 用于展示考试结果的界面。 + * 用于展示考试结果的界面. */ public class ExamResultsView extends BorderPane { @@ -24,72 +26,74 @@ public class ExamResultsView extends BorderPane { private Button exitButton; /** - * ExamResultsView 的构造函数。 + * ExamResultsView 的构造函数. * * @param primaryStage 应用程序的主舞台 - * @param controller 数学学习控制器 - * @param examSession 已完成的考试会话 + * @param controller 数学学习控制器 + * @param examSession 已完成的考试会话 */ - public ExamResultsView(Stage primaryStage, MathLearningController controller, ExamSession examSession) { + public ExamResultsView(Stage primaryStage, MathLearningController controller, + ExamSession examSession) { this.primaryStage = primaryStage; this.controller = controller; this.examSession = examSession; - initializeUI(); + initializeUi(); } /** - * 初始化界面组件。 + * 初始化界面组件. */ - private void initializeUI() { + private void initializeUi() { // 创建主布局 VBox mainLayout = new VBox(20); mainLayout.setAlignment(Pos.CENTER); mainLayout.setPadding(new Insets(20)); - + // 结果标题 Label titleLabel = new Label("考试结果"); titleLabel.setFont(Font.font("System", FontWeight.BOLD, 24)); - + // 分数展示 double score = examSession.calculateScore(); - Label scoreLabel = new Label(String.format("您的得分: %.2f%%", score)); + Label scoreLabel = new Label(String.format("您的得分: %.2f", score)); scoreLabel.setFont(Font.font("System", FontWeight.BOLD, 18)); - + // 成绩明细 VBox breakdownBox = new VBox(10); breakdownBox.setAlignment(Pos.CENTER); - + Label totalQuestionsLabel = new Label("总题数: " + examSession.getTotalQuestions()); Label correctAnswersLabel = new Label("答对题数: " + examSession.getCorrectAnswersCount()); Label incorrectAnswersLabel = new Label("答错题数: " + examSession.getIncorrectAnswersCount()); - - breakdownBox.getChildren().addAll(totalQuestionsLabel, correctAnswersLabel, incorrectAnswersLabel); - + + breakdownBox.getChildren() + .addAll(totalQuestionsLabel, correctAnswersLabel, incorrectAnswersLabel); + // 按钮区域 HBox buttonBox = new HBox(15); buttonBox.setAlignment(Pos.CENTER); - + continueButton = new Button("继续考试"); exitButton = new Button("退出"); - + // 设置按钮尺寸 continueButton.setPrefSize(120, 40); exitButton.setPrefSize(120, 40); - + buttonBox.getChildren().addAll(continueButton, exitButton); - + // 将组件添加到主布局 mainLayout.getChildren().addAll(titleLabel, scoreLabel, breakdownBox, buttonBox); - + // 将主布局置于边界面板中央 setCenter(mainLayout); - + // 添加事件处理器 addEventHandlers(); } /** - * 为界面组件添加事件处理器。 + * 为界面组件添加事件处理器. */ private void addEventHandlers() { continueButton.setOnAction(e -> handleContinue()); @@ -97,7 +101,7 @@ public class ExamResultsView extends BorderPane { } /** - * 处理继续考试按钮的操作。 + * 处理继续考试按钮的操作. */ private void handleContinue() { // 返回主菜单以开始新考试 @@ -111,7 +115,7 @@ public class ExamResultsView extends BorderPane { // 如果找不到用户信息,则提示错误并返回登录界面 showAlert(Alert.AlertType.ERROR, "错误", "用户信息无法找到,请重新登录"); // 返回登录场景 - com.personalproject.ui.scenes.LoginScene loginScene = + com.personalproject.ui.scenes.LoginScene loginScene = new com.personalproject.ui.scenes.LoginScene(primaryStage, controller); primaryStage.getScene().setRoot(loginScene); } @@ -119,7 +123,7 @@ public class ExamResultsView extends BorderPane { } /** - * 处理退出按钮的操作。 + * 处理退出按钮的操作. */ private void handleExit() { // 返回主菜单 @@ -133,7 +137,7 @@ public class ExamResultsView extends BorderPane { // 如果找不到用户信息,则提示错误并返回登录界面 showAlert(Alert.AlertType.ERROR, "错误", "用户信息无法找到,请重新登录"); // 返回登录场景 - com.personalproject.ui.scenes.LoginScene loginScene = + com.personalproject.ui.scenes.LoginScene loginScene = new com.personalproject.ui.scenes.LoginScene(primaryStage, controller); primaryStage.getScene().setRoot(loginScene); } @@ -141,11 +145,11 @@ public class ExamResultsView extends BorderPane { } /** - * 显示提示对话框。 + * 显示提示对话框. * * @param alertType 提示类型 - * @param title 对话框标题 - * @param message 显示的消息 + * @param title 对话框标题 + * @param message 显示的消息 */ private void showAlert(Alert.AlertType alertType, String title, String message) { Alert alert = new Alert(alertType); diff --git a/src/main/java/com/personalproject/ui/views/ExamSelectionView.java b/src/main/java/com/personalproject/ui/views/ExamSelectionView.java index 839b54f..2a2d640 100644 --- a/src/main/java/com/personalproject/ui/views/ExamSelectionView.java +++ b/src/main/java/com/personalproject/ui/views/ExamSelectionView.java @@ -1,18 +1,25 @@ package com.personalproject.ui.views; +import com.personalproject.auth.UserAccount; +import com.personalproject.controller.MathLearningController; +import com.personalproject.model.DifficultyLevel; import javafx.geometry.Insets; import javafx.geometry.Pos; -import javafx.scene.control.*; -import javafx.scene.layout.*; +import javafx.scene.control.Alert; +import javafx.scene.control.Button; +import javafx.scene.control.ComboBox; +import javafx.scene.control.Label; +import javafx.scene.control.Spinner; +import javafx.scene.layout.BorderPane; +import javafx.scene.layout.GridPane; +import javafx.scene.layout.HBox; +import javafx.scene.layout.VBox; import javafx.scene.text.Font; import javafx.scene.text.FontWeight; import javafx.stage.Stage; -import com.personalproject.controller.MathLearningController; -import com.personalproject.model.DifficultyLevel; -import com.personalproject.auth.UserAccount; /** - * 用于选择考试难度和题目数量的界面。 + * 用于选择考试难度和题目数量的界面. */ public class ExamSelectionView extends BorderPane { @@ -25,78 +32,80 @@ public class ExamSelectionView extends BorderPane { private Button backButton; /** - * ExamSelectionView 的构造函数。 + * ExamSelectionView 的构造函数. * * @param primaryStage 应用程序的主舞台 - * @param controller 数学学习控制器 - * @param userAccount 当前用户账户 + * @param controller 数学学习控制器 + * @param userAccount 当前用户账户 */ - public ExamSelectionView(Stage primaryStage, MathLearningController controller, UserAccount userAccount) { + public ExamSelectionView(Stage primaryStage, MathLearningController controller, + UserAccount userAccount) { this.primaryStage = primaryStage; this.controller = controller; this.userAccount = userAccount; - initializeUI(); + initializeUi(); } /** - * 初始化界面组件。 + * 初始化界面组件. */ - private void initializeUI() { + private void initializeUi() { // 创建主布局 VBox mainLayout = new VBox(20); mainLayout.setAlignment(Pos.CENTER); mainLayout.setPadding(new Insets(20)); - + // 标题 - Label titleLabel = new Label("考试设置"); + final Label titleLabel = new Label("考试设置"); titleLabel.setFont(Font.font("System", FontWeight.BOLD, 24)); - + // 考试设置表单 GridPane examSettingsForm = new GridPane(); examSettingsForm.setHgap(15); examSettingsForm.setVgap(15); examSettingsForm.setAlignment(Pos.CENTER); - - Label difficultyLabel = new Label("选择难度:"); + + final Label difficultyLabel = new Label("选择难度:"); difficultyComboBox = new ComboBox<>(); - difficultyComboBox.getItems().addAll(DifficultyLevel.PRIMARY, DifficultyLevel.MIDDLE, DifficultyLevel.HIGH); + difficultyComboBox.getItems() + .addAll(DifficultyLevel.PRIMARY, DifficultyLevel.MIDDLE, DifficultyLevel.HIGH); difficultyComboBox.setValue(userAccount.difficultyLevel()); // 默认选中用户的难度 difficultyComboBox.setPrefWidth(200); - - Label questionCountLabel = new Label("题目数量 (10-30):"); + + final Label questionCountLabel = new Label("题目数量 (10-30):"); questionCountSpinner = new Spinner<>(10, 30, 10); // 最小值、最大值、初始值 questionCountSpinner.setPrefWidth(200); - + examSettingsForm.add(difficultyLabel, 0, 0); examSettingsForm.add(difficultyComboBox, 1, 0); examSettingsForm.add(questionCountLabel, 0, 1); examSettingsForm.add(questionCountSpinner, 1, 1); - + // 按钮区域 HBox buttonBox = new HBox(15); buttonBox.setAlignment(Pos.CENTER); - + startExamButton = new Button("开始考试"); backButton = new Button("返回"); - + // 设置按钮尺寸 startExamButton.setPrefSize(120, 40); backButton.setPrefSize(120, 40); - + buttonBox.getChildren().addAll(startExamButton, backButton); - + // 将组件添加到主布局 mainLayout.getChildren().addAll(titleLabel, examSettingsForm, buttonBox); - + // 将主布局置于边界面板中央 setCenter(mainLayout); - + // 添加事件处理器 addEventHandlers(); } /** - * 为界面组件添加事件处理器。 + * 为界面组件添加事件处理器. */ private void addEventHandlers() { startExamButton.setOnAction(e -> handleStartExam()); @@ -104,27 +113,27 @@ public class ExamSelectionView extends BorderPane { } /** - * 处理开始考试按钮的操作。 + * 处理开始考试按钮的操作. */ private void handleStartExam() { DifficultyLevel selectedDifficulty = difficultyComboBox.getValue(); int questionCount = questionCountSpinner.getValue(); - + if (questionCount < 10 || questionCount > 30) { showAlert(Alert.AlertType.WARNING, "无效输入", "题目数量必须在10到30之间"); return; } - + // 创建并启动考试会话 com.personalproject.model.ExamSession examSession = controller.createExamSession( userAccount.username(), selectedDifficulty, questionCount); - + ExamView examView = new ExamView(primaryStage, controller, examSession); primaryStage.getScene().setRoot(examView); } /** - * 处理返回按钮的操作。 + * 处理返回按钮的操作. */ private void handleBack() { MainMenuView mainMenuView = new MainMenuView(primaryStage, controller, userAccount); @@ -132,11 +141,11 @@ public class ExamSelectionView extends BorderPane { } /** - * 显示提示对话框。 + * 显示提示对话框. * * @param alertType 提示类型 - * @param title 对话框标题 - * @param message 显示的消息 + * @param title 对话框标题 + * @param message 显示的消息 */ private void showAlert(Alert.AlertType alertType, String title, String message) { Alert alert = new Alert(alertType); diff --git a/src/main/java/com/personalproject/ui/views/ExamView.java b/src/main/java/com/personalproject/ui/views/ExamView.java index 02f2363..2ff4b17 100644 --- a/src/main/java/com/personalproject/ui/views/ExamView.java +++ b/src/main/java/com/personalproject/ui/views/ExamView.java @@ -1,19 +1,24 @@ package com.personalproject.ui.views; +import com.personalproject.controller.MathLearningController; +import com.personalproject.model.ExamSession; +import com.personalproject.model.QuizQuestion; import javafx.geometry.Insets; import javafx.geometry.Pos; -import javafx.scene.control.*; -import javafx.scene.layout.*; +import javafx.scene.control.Alert; +import javafx.scene.control.Button; +import javafx.scene.control.Label; +import javafx.scene.control.RadioButton; +import javafx.scene.control.ToggleGroup; +import javafx.scene.layout.BorderPane; +import javafx.scene.layout.HBox; +import javafx.scene.layout.VBox; import javafx.scene.text.Font; import javafx.scene.text.FontWeight; import javafx.stage.Stage; -import com.personalproject.controller.MathLearningController; -import com.personalproject.model.ExamSession; -import com.personalproject.model.QuizQuestion; -import com.personalproject.ui.views.ExamResultsView; /** - * 提供答题界面以及题目与选项的呈现。 + * 提供答题界面以及题目与选项的呈现. */ public class ExamView extends BorderPane { @@ -30,73 +35,73 @@ public class ExamView extends BorderPane { private HBox buttonBox; /** - * ExamView 的构造函数。 + * ExamView 的构造函数. * * @param primaryStage 应用程序的主舞台 - * @param controller 数学学习控制器 - * @param examSession 当前的考试会话 + * @param controller 数学学习控制器 + * @param examSession 当前的考试会话 */ public ExamView(Stage primaryStage, MathLearningController controller, ExamSession examSession) { this.primaryStage = primaryStage; this.controller = controller; this.examSession = examSession; - initializeUI(); + initializeUi(); } /** - * 初始化界面组件。 + * 初始化界面组件. */ - private void initializeUI() { + private void initializeUi() { // 创建主布局 VBox mainLayout = new VBox(20); mainLayout.setAlignment(Pos.CENTER); mainLayout.setPadding(new Insets(20)); - + // 题号 questionNumberLabel = new Label(); questionNumberLabel.setFont(Font.font("System", FontWeight.BOLD, 16)); - + // 题目文本 questionTextLabel = new Label(); questionTextLabel.setWrapText(true); questionTextLabel.setFont(Font.font("System", FontWeight.NORMAL, 14)); questionTextLabel.setMaxWidth(500); - + // 选项容器 optionsBox = new VBox(10); optionsBox.setPadding(new Insets(10)); answerToggleGroup = new ToggleGroup(); - + // 按钮区域 buttonBox = new HBox(15); buttonBox.setAlignment(Pos.CENTER); - + previousButton = new Button("上一题"); nextButton = new Button("下一题"); finishButton = new Button("完成考试"); - + // 设置按钮尺寸 previousButton.setPrefSize(100, 35); nextButton.setPrefSize(100, 35); finishButton.setPrefSize(120, 35); - + buttonBox.getChildren().addAll(previousButton, nextButton, finishButton); - + // 将组件添加到主布局 mainLayout.getChildren().addAll(questionNumberLabel, questionTextLabel, optionsBox, buttonBox); - + // 将主布局置于边界面板中央 setCenter(mainLayout); - + // 加载第一题 loadCurrentQuestion(); - + // 添加事件处理器 addEventHandlers(); } /** - * 将当前题目加载到界面。 + * 将当前题目加载到界面. */ private void loadCurrentQuestion() { try { @@ -106,24 +111,24 @@ public class ExamView extends BorderPane { updateButtonStates(); return; } - + QuizQuestion currentQuestion = examSession.getCurrentQuestion(); int currentIndex = examSession.getCurrentQuestionIndex(); - + if (currentQuestion == null) { showAlert(Alert.AlertType.ERROR, "错误", "当前题目为空,请重新开始考试"); return; } - + // 更新题号与题目文本 questionNumberLabel.setText("第 " + (currentIndex + 1) + " 题"); questionTextLabel.setText(currentQuestion.getQuestionText()); - + // 清空上一题的选项 answerToggleGroup.selectToggle(null); answerToggleGroup.getToggles().clear(); optionsBox.getChildren().clear(); - + // 创建新的选项组件 for (int i = 0; i < currentQuestion.getOptions().size(); i++) { String option = currentQuestion.getOptions().get(i); @@ -132,14 +137,14 @@ public class ExamView extends BorderPane { optionButton.setUserData(i); // 存储选项索引 // 如果该题已有答案则自动选中 - if (examSession.hasAnswered(currentIndex) && - examSession.getUserAnswer(currentIndex) == i) { + if (examSession.hasAnswered(currentIndex) + && examSession.getUserAnswer(currentIndex) == i) { optionButton.setSelected(true); } - + optionsBox.getChildren().add(optionButton); } - + // 更新按钮状态 updateButtonStates(); } catch (Exception e) { @@ -148,13 +153,13 @@ public class ExamView extends BorderPane { } /** - * 根据当前位置更新导航按钮的状态。 + * 根据当前位置更新导航按钮的状态. */ private void updateButtonStates() { try { int currentIndex = examSession.getCurrentQuestionIndex(); int totalQuestions = examSession.getTotalQuestions(); - + // 处理潜在极端情况 if (totalQuestions <= 0) { // 如果没有题目,则禁用所有导航按钮 @@ -163,13 +168,13 @@ public class ExamView extends BorderPane { finishButton.setDisable(false); // 仍允许完成考试 return; } - + // “上一题”按钮状态 previousButton.setDisable(currentIndex < 0 || currentIndex == 0); - + // “下一题”按钮状态 nextButton.setDisable(currentIndex < 0 || currentIndex >= totalQuestions - 1); - + // “完成考试”按钮状态——在考试完成或到达最后一题时启用 boolean isExamComplete = examSession.isComplete(); boolean isAtLastQuestion = (currentIndex >= totalQuestions - 1); @@ -184,13 +189,13 @@ public class ExamView extends BorderPane { } /** - * 为界面组件添加事件处理器。 + * 为界面组件添加事件处理器. */ private void addEventHandlers() { nextButton.setOnAction(e -> handleNextQuestion()); previousButton.setOnAction(e -> handlePreviousQuestion()); finishButton.setOnAction(e -> handleFinishExam()); - + // 添加变更监听器,在选项被选择时保存答案 answerToggleGroup.selectedToggleProperty().addListener((obs, oldSelection, newSelection) -> { if (newSelection != null) { @@ -201,7 +206,7 @@ public class ExamView extends BorderPane { } /** - * 处理“下一题”按钮的操作。 + * 处理“下一题”按钮的操作. */ private void handleNextQuestion() { try { @@ -218,7 +223,7 @@ public class ExamView extends BorderPane { } /** - * 处理“上一题”按钮的操作。 + * 处理“上一题”按钮的操作. */ private void handlePreviousQuestion() { try { @@ -234,11 +239,11 @@ public class ExamView extends BorderPane { } /** - * 显示提示对话框。 + * 显示提示对话框. * * @param alertType 提示类型 - * @param title 对话框标题 - * @param message 显示的消息 + * @param title 对话框标题 + * @param message 显示的消息 */ private void showAlert(Alert.AlertType alertType, String title, String message) { Alert alert = new Alert(alertType); @@ -249,12 +254,12 @@ public class ExamView extends BorderPane { } /** - * 处理“完成考试”按钮的操作。 + * 处理“完成考试”按钮的操作. */ private void handleFinishExam() { // 保存考试结果 controller.saveExamResults(examSession); - + // 展示考试结果 ExamResultsView resultsView = new ExamResultsView(primaryStage, controller, examSession); primaryStage.getScene().setRoot(resultsView); diff --git a/src/main/java/com/personalproject/ui/views/MainMenuView.java b/src/main/java/com/personalproject/ui/views/MainMenuView.java index 619ca88..7866b73 100644 --- a/src/main/java/com/personalproject/ui/views/MainMenuView.java +++ b/src/main/java/com/personalproject/ui/views/MainMenuView.java @@ -1,113 +1,165 @@ package com.personalproject.ui.views; +import com.personalproject.auth.UserAccount; +import com.personalproject.controller.MathLearningController; +import com.personalproject.model.DifficultyLevel; +import com.personalproject.ui.scenes.LoginScene; +import java.util.Optional; import javafx.geometry.Insets; import javafx.geometry.Pos; -import javafx.scene.control.*; -import javafx.scene.layout.*; +import javafx.scene.control.Alert; +import javafx.scene.control.Button; +import javafx.scene.control.Label; +import javafx.scene.control.TextInputDialog; +import javafx.scene.layout.BorderPane; +import javafx.scene.layout.VBox; import javafx.scene.text.Font; import javafx.scene.text.FontWeight; import javafx.stage.Stage; -import com.personalproject.controller.MathLearningController; -import com.personalproject.model.DifficultyLevel; -import com.personalproject.model.ExamSession; -import com.personalproject.auth.UserAccount; -import com.personalproject.ui.scenes.LoginScene; /** - * 用户可以开始考试或更改设置的主菜单界面。 + * 用户可以开始考试或更改设置的主菜单界面. */ public class MainMenuView extends BorderPane { private final Stage primaryStage; private final MathLearningController controller; private final UserAccount userAccount; - private Button startExamButton; private Button changePasswordButton; private Button logoutButton; /** - * MainMenuView 的构造函数。 + * MainMenuView 的构造函数. * * @param primaryStage 应用程序的主舞台 - * @param controller 数学学习控制器 - * @param userAccount 当前用户账户 + * @param controller 数学学习控制器 + * @param userAccount 当前用户账户 */ - public MainMenuView(Stage primaryStage, MathLearningController controller, UserAccount userAccount) { + public MainMenuView(Stage primaryStage, MathLearningController controller, + UserAccount userAccount) { this.primaryStage = primaryStage; this.controller = controller; this.userAccount = userAccount; - initializeUI(); + initializeUi(); } /** - * 初始化界面组件。 + * 初始化界面组件. */ - private void initializeUI() { + private void initializeUi() { // 创建主布局 VBox mainLayout = new VBox(20); mainLayout.setAlignment(Pos.CENTER); mainLayout.setPadding(new Insets(20)); - + // 欢迎信息 Label welcomeLabel = new Label("欢迎, " + userAccount.username()); welcomeLabel.setFont(Font.font("System", FontWeight.BOLD, 18)); - + // 难度信息 - Label difficultyLabel = new Label("当前难度: " + userAccount.difficultyLevel().getDisplayName()); + Label difficultyLabel = new Label( + "当前难度: " + userAccount.difficultyLevel().getDisplayName()); difficultyLabel.setFont(Font.font("System", FontWeight.NORMAL, 14)); - + + Label promptLabel = new Label("请选择考试难度开始答题"); + promptLabel.setFont(Font.font("System", FontWeight.NORMAL, 14)); + + VBox difficultyBox = new VBox(10); + difficultyBox.setAlignment(Pos.CENTER); + difficultyBox.getChildren().addAll( + createDifficultyButton(DifficultyLevel.PRIMARY), + createDifficultyButton(DifficultyLevel.MIDDLE), + createDifficultyButton(DifficultyLevel.HIGH)); + // 按钮区域 VBox buttonBox = new VBox(15); buttonBox.setAlignment(Pos.CENTER); - - startExamButton = new Button("开始考试"); + changePasswordButton = new Button("修改密码"); logoutButton = new Button("退出登录"); - + // 设置按钮尺寸 - startExamButton.setPrefSize(150, 40); changePasswordButton.setPrefSize(150, 40); logoutButton.setPrefSize(150, 40); - - buttonBox.getChildren().addAll(startExamButton, changePasswordButton, logoutButton); - + + buttonBox.getChildren().addAll(changePasswordButton, logoutButton); + // 将组件添加到主布局 - mainLayout.getChildren().addAll(welcomeLabel, difficultyLabel, buttonBox); - + mainLayout.getChildren().addAll(welcomeLabel, difficultyLabel, promptLabel, difficultyBox, + buttonBox); + // 将主布局置于边界面板中央 setCenter(mainLayout); - + // 添加事件处理器 addEventHandlers(); } /** - * 为界面组件添加事件处理器。 + * 为界面组件添加事件处理器. */ private void addEventHandlers() { - startExamButton.setOnAction(e -> handleStartExam()); changePasswordButton.setOnAction(e -> handleChangePassword()); logoutButton.setOnAction(e -> handleLogout()); } - /** - * 处理开始考试按钮的操作。 - */ - private void handleStartExam() { - ExamSelectionView examSelectionView = new ExamSelectionView(primaryStage, controller, userAccount); - primaryStage.getScene().setRoot(examSelectionView); + private Button createDifficultyButton(DifficultyLevel level) { + Button button = new Button(level.getDisplayName()); + button.setPrefSize(150, 40); + button.setOnAction(e -> handleDifficultySelection(level)); + return button; + } + + private void handleDifficultySelection(DifficultyLevel level) { + TextInputDialog dialog = new TextInputDialog("10"); + dialog.setTitle("题目数量"); + dialog.setHeaderText("请选择题目数量"); + dialog.setContentText("请输入题目数量 (10-30):"); + + Optional result = dialog.showAndWait(); + if (result.isEmpty()) { + return; + } + + int questionCount; + try { + questionCount = Integer.parseInt(result.get().trim()); + } catch (NumberFormatException ex) { + showAlert(Alert.AlertType.ERROR, "无效输入", "请输入有效的数字。"); + return; + } + + if (questionCount < 10 || questionCount > 30) { + showAlert(Alert.AlertType.WARNING, "题目数量范围错误", "题目数量必须在10到30之间。"); + return; + } + + com.personalproject.model.ExamSession examSession = controller.createExamSession( + userAccount.username(), level, questionCount); + + ExamView examView = new ExamView(primaryStage, controller, examSession); + primaryStage.getScene().setRoot(examView); } /** - * 处理修改密码按钮的操作。 + * 处理修改密码按钮的操作. */ private void handleChangePassword() { - PasswordChangeView passwordChangeView = new PasswordChangeView(primaryStage, controller, userAccount); + PasswordChangeView passwordChangeView = new PasswordChangeView(primaryStage, controller, + userAccount); primaryStage.getScene().setRoot(passwordChangeView); } + private void showAlert(Alert.AlertType alertType, String title, String message) { + Alert alert = new Alert(alertType); + alert.setTitle(title); + alert.setHeaderText(null); + alert.setContentText(message); + alert.showAndWait(); + } + /** - * 处理退出登录按钮的操作。 + * 处理退出登录按钮的操作. */ private void handleLogout() { // 返回登录界面 diff --git a/src/main/java/com/personalproject/ui/views/PasswordChangeView.java b/src/main/java/com/personalproject/ui/views/PasswordChangeView.java index ef28098..4a55267 100644 --- a/src/main/java/com/personalproject/ui/views/PasswordChangeView.java +++ b/src/main/java/com/personalproject/ui/views/PasswordChangeView.java @@ -1,18 +1,23 @@ package com.personalproject.ui.views; +import com.personalproject.auth.UserAccount; +import com.personalproject.controller.MathLearningController; import javafx.geometry.Insets; import javafx.geometry.Pos; -import javafx.scene.control.*; -import javafx.scene.layout.*; +import javafx.scene.control.Alert; +import javafx.scene.control.Button; +import javafx.scene.control.Label; +import javafx.scene.control.PasswordField; +import javafx.scene.layout.BorderPane; +import javafx.scene.layout.GridPane; +import javafx.scene.layout.HBox; +import javafx.scene.layout.VBox; import javafx.scene.text.Font; import javafx.scene.text.FontWeight; import javafx.stage.Stage; -import com.personalproject.controller.MathLearningController; -import com.personalproject.auth.UserAccount; -import com.personalproject.ui.views.MainMenuView; /** - * 用户修改密码的界面。 + * 用户修改密码的界面. */ public class PasswordChangeView extends BorderPane { @@ -26,82 +31,83 @@ public class PasswordChangeView extends BorderPane { private Button backButton; /** - * PasswordChangeView 的构造函数。 + * PasswordChangeView 的构造函数. * * @param primaryStage 应用程序的主舞台 - * @param controller 数学学习控制器 - * @param userAccount 当前用户账户 + * @param controller 数学学习控制器 + * @param userAccount 当前用户账户 */ - public PasswordChangeView(Stage primaryStage, MathLearningController controller, UserAccount userAccount) { + public PasswordChangeView(Stage primaryStage, MathLearningController controller, + UserAccount userAccount) { this.primaryStage = primaryStage; this.controller = controller; this.userAccount = userAccount; - initializeUI(); + initializeUi(); } /** - * 初始化界面组件。 + * 初始化界面组件. */ - private void initializeUI() { + private void initializeUi() { // 创建主布局 VBox mainLayout = new VBox(20); mainLayout.setAlignment(Pos.CENTER); mainLayout.setPadding(new Insets(20)); - + // 标题 - Label titleLabel = new Label("修改密码"); + final Label titleLabel = new Label("修改密码"); titleLabel.setFont(Font.font("System", FontWeight.BOLD, 24)); - + // 修改密码表单 GridPane passwordForm = new GridPane(); passwordForm.setHgap(15); passwordForm.setVgap(15); passwordForm.setAlignment(Pos.CENTER); - - Label oldPasswordLabel = new Label("当前密码:"); + + final Label oldPasswordLabel = new Label("当前密码:"); oldPasswordField = new PasswordField(); oldPasswordField.setPrefWidth(200); - - Label newPasswordLabel = new Label("新密码 (6-10位,包含大小写字母和数字):"); + + final Label newPasswordLabel = new Label("新密码 (6-10位,包含大小写字母和数字):"); newPasswordField = new PasswordField(); newPasswordField.setPrefWidth(200); - - Label confirmNewPasswordLabel = new Label("确认新密码:"); + + final Label confirmNewPasswordLabel = new Label("确认新密码:"); confirmNewPasswordField = new PasswordField(); confirmNewPasswordField.setPrefWidth(200); - + passwordForm.add(oldPasswordLabel, 0, 0); passwordForm.add(oldPasswordField, 1, 0); passwordForm.add(newPasswordLabel, 0, 1); passwordForm.add(newPasswordField, 1, 1); passwordForm.add(confirmNewPasswordLabel, 0, 2); passwordForm.add(confirmNewPasswordField, 1, 2); - + // 按钮区域 HBox buttonBox = new HBox(15); buttonBox.setAlignment(Pos.CENTER); - + changePasswordButton = new Button("修改密码"); backButton = new Button("返回"); - + // 设置按钮尺寸 changePasswordButton.setPrefSize(120, 40); backButton.setPrefSize(120, 40); - + buttonBox.getChildren().addAll(changePasswordButton, backButton); - + // 将组件添加到主布局 mainLayout.getChildren().addAll(titleLabel, passwordForm, buttonBox); - + // 将主布局置于边界面板中央 setCenter(mainLayout); - + // 添加事件处理器 addEventHandlers(); } /** - * 为界面组件添加事件处理器。 + * 为界面组件添加事件处理器. */ private void addEventHandlers() { changePasswordButton.setOnAction(e -> handleChangePassword()); @@ -109,7 +115,7 @@ public class PasswordChangeView extends BorderPane { } /** - * 处理修改密码按钮的操作。 + * 处理修改密码按钮的操作. */ private void handleChangePassword() { String oldPassword = oldPasswordField.getText(); @@ -127,7 +133,7 @@ public class PasswordChangeView extends BorderPane { } if (!controller.isValidPassword(newPassword)) { - showAlert(Alert.AlertType.ERROR, "密码不符合要求", + showAlert(Alert.AlertType.ERROR, "密码不符合要求", "密码长度必须为6-10位,且包含大小写字母和数字"); return; } @@ -143,7 +149,7 @@ public class PasswordChangeView extends BorderPane { } /** - * 处理返回按钮的操作。 + * 处理返回按钮的操作. */ private void handleBack() { MainMenuView mainMenuView = new MainMenuView(primaryStage, controller, userAccount); @@ -151,11 +157,11 @@ public class PasswordChangeView extends BorderPane { } /** - * 显示提示对话框。 + * 显示提示对话框. * * @param alertType 提示类型 - * @param title 对话框标题 - * @param message 显示的消息 + * @param title 对话框标题 + * @param message 显示的消息 */ private void showAlert(Alert.AlertType alertType, String title, String message) { Alert alert = new Alert(alertType); diff --git a/src/main/resources/email-config.properties b/src/main/resources/email-config.properties index 71ce04e..db546dc 100644 --- a/src/main/resources/email-config.properties +++ b/src/main/resources/email-config.properties @@ -17,4 +17,4 @@ mail.username=soloyouth@126.com mail.password=ZYsjxwDXFBsWeQcX mail.from=soloyouth@126.com mail.subject=数学学习软件注册验证码 -mail.debug=true \ No newline at end of file +mail.debug=true