|
|
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.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.ScrollPane;
|
|
|
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;
|
|
|
|
|
|
/**
|
|
|
* 负责处理用户注册的场景.
|
|
|
*/
|
|
|
public class RegistrationScene extends BorderPane {
|
|
|
|
|
|
private final Stage primaryStage;
|
|
|
private final MathLearningController controller;
|
|
|
private TextField usernameField;
|
|
|
private TextField emailField;
|
|
|
private ComboBox<DifficultyLevel> difficultyComboBox;
|
|
|
private Button sendCodeButton;
|
|
|
private TextField registrationCodeField;
|
|
|
private Button verifyCodeButton;
|
|
|
private PasswordField passwordField;
|
|
|
private PasswordField confirmPasswordField;
|
|
|
private Button setPasswordButton;
|
|
|
private Button backButton;
|
|
|
private VBox registrationForm;
|
|
|
|
|
|
/**
|
|
|
* RegistrationScene 的构造函数.
|
|
|
*
|
|
|
* @param primaryStage 应用程序的主舞台
|
|
|
* @param controller 数学学习控制器
|
|
|
*/
|
|
|
public RegistrationScene(Stage primaryStage, MathLearningController controller) {
|
|
|
this.primaryStage = primaryStage;
|
|
|
this.controller = controller;
|
|
|
initializeUi();
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* 初始化界面组件.
|
|
|
*/
|
|
|
private void initializeUi() {
|
|
|
// 创建主布局
|
|
|
VBox mainLayout = new VBox(15);
|
|
|
mainLayout.setAlignment(Pos.TOP_CENTER);
|
|
|
mainLayout.setPadding(new Insets(20));
|
|
|
|
|
|
// 标题
|
|
|
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);
|
|
|
|
|
|
final Label usernameLabel = new Label("用户名:");
|
|
|
usernameField = new TextField();
|
|
|
usernameField.setPrefWidth(200);
|
|
|
|
|
|
final Label emailLabel = new Label("邮箱:");
|
|
|
emailField = new TextField();
|
|
|
emailField.setPrefWidth(200);
|
|
|
|
|
|
final Label difficultyLabel = new Label("默认难度:");
|
|
|
difficultyComboBox = new ComboBox<>();
|
|
|
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);
|
|
|
|
|
|
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);
|
|
|
|
|
|
final Label passwordLabel = new Label("设置密码 (6-10位,包含大小写字母和数字):");
|
|
|
passwordField = new PasswordField();
|
|
|
passwordField.setPrefWidth(200);
|
|
|
|
|
|
final Label confirmPasswordLabel = new Label("确认密码:");
|
|
|
confirmPasswordField = new PasswordField();
|
|
|
confirmPasswordField.setPrefWidth(200);
|
|
|
|
|
|
setPasswordButton = new Button("设置密码");
|
|
|
setPasswordButton.setPrefWidth(120);
|
|
|
|
|
|
passwordSection.getChildren().addAll(passwordLabel, passwordField, confirmPasswordLabel,
|
|
|
confirmPasswordField, setPasswordButton);
|
|
|
registrationForm.getChildren().add(passwordSection);
|
|
|
|
|
|
// 返回按钮
|
|
|
backButton = new Button("返回");
|
|
|
backButton.setPrefWidth(100);
|
|
|
|
|
|
// 将组件添加到主布局
|
|
|
mainLayout.getChildren().addAll(titleLabel, registrationForm, backButton);
|
|
|
|
|
|
// 使用可滚动容器保证内容在小窗口中完整显示
|
|
|
ScrollPane scrollPane = new ScrollPane(mainLayout);
|
|
|
scrollPane.setFitToWidth(true);
|
|
|
scrollPane.setHbarPolicy(ScrollPane.ScrollBarPolicy.NEVER);
|
|
|
setCenter(scrollPane);
|
|
|
|
|
|
// 添加事件处理器
|
|
|
addEventHandlers(sendCodeButton, verificationSection, verifyCodeButton, passwordSection);
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* 为界面组件添加事件处理器.
|
|
|
*/
|
|
|
private void addEventHandlers(Button sendCodeButton, VBox verificationSection,
|
|
|
Button verifyCodeButton, VBox passwordSection) {
|
|
|
sendCodeButton.setOnAction(e -> handleSendCode(verificationSection));
|
|
|
verifyCodeButton.setOnAction(e -> handleVerifyCode(passwordSection));
|
|
|
setPasswordButton.setOnAction(e -> handleSetPassword());
|
|
|
backButton.setOnAction(e -> handleBack());
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* 处理发送注册码的逻辑.
|
|
|
*/
|
|
|
private void handleSendCode(VBox verificationSection) {
|
|
|
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, "警告", "请输入用户名和邮箱");
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
if (!controller.isValidEmail(email)) {
|
|
|
showAlert(Alert.AlertType.ERROR, "邮箱格式错误", "请输入有效的邮箱地址");
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
// 发起注册
|
|
|
boolean success = controller.initiateRegistration(username, email, difficultyLevel);
|
|
|
|
|
|
if (success) {
|
|
|
showAlert(Alert.AlertType.INFORMATION, "注册码已发送", "注册码已发送至您的邮箱,请查收。");
|
|
|
verificationSection.setVisible(true);
|
|
|
verificationSection.setManaged(true);
|
|
|
} else {
|
|
|
showAlert(Alert.AlertType.ERROR, "注册失败", "用户名或邮箱可能已存在,请重试。");
|
|
|
}
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* 处理注册码验证.
|
|
|
*/
|
|
|
private void handleVerifyCode(VBox passwordSection) {
|
|
|
final String username = usernameField.getText().trim();
|
|
|
final String registrationCode = registrationCodeField.getText().trim();
|
|
|
|
|
|
if (registrationCode.isEmpty()) {
|
|
|
showAlert(Alert.AlertType.WARNING, "警告", "请输入注册码");
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
boolean verified = controller.verifyRegistrationCode(username, registrationCode);
|
|
|
|
|
|
if (verified) {
|
|
|
showAlert(Alert.AlertType.INFORMATION, "验证成功", "注册码验证成功!");
|
|
|
passwordSection.setVisible(true);
|
|
|
passwordSection.setManaged(true);
|
|
|
} else {
|
|
|
showAlert(Alert.AlertType.ERROR, "验证失败", "注册码验证失败,请检查后重试。");
|
|
|
}
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* 处理设置用户密码的逻辑.
|
|
|
*/
|
|
|
private void handleSetPassword() {
|
|
|
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, "警告", "请输入并确认密码");
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
if (!password.equals(confirmPassword)) {
|
|
|
showAlert(Alert.AlertType.ERROR, "密码不匹配", "两次输入的密码不一致");
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
if (!controller.isValidPassword(password)) {
|
|
|
showAlert(Alert.AlertType.ERROR, "密码不符合要求",
|
|
|
"密码长度必须为6-10位,且包含大小写字母和数字");
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
boolean success = controller.setPassword(username, password);
|
|
|
|
|
|
if (success) {
|
|
|
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);
|
|
|
primaryStage.getScene().setRoot(loginScene);
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* 显示提示对话框.
|
|
|
*
|
|
|
* @param alertType 提示类型
|
|
|
* @param title 对话框标题
|
|
|
* @param message 显示的消息
|
|
|
*/
|
|
|
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();
|
|
|
}
|
|
|
}
|