|
|
|
|
@ -45,7 +45,24 @@ public class ExamController {
|
|
|
|
|
@FXML private Button logoutButton;
|
|
|
|
|
@FXML private Label statusLabel;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 添加设置密码面板相关控件引用(需要在FXML中添加对应控件)
|
|
|
|
|
@FXML private VBox setPasswordPanel;
|
|
|
|
|
@FXML private PasswordField setPasswordField;
|
|
|
|
|
@FXML private PasswordField confirmPasswordField;
|
|
|
|
|
@FXML private Button confirmSetPasswordButton;
|
|
|
|
|
@FXML private Label setPasswordStatusLabel;
|
|
|
|
|
|
|
|
|
|
// 添加修改密码面板相关控件引用
|
|
|
|
|
@FXML private VBox changePasswordPanel;
|
|
|
|
|
@FXML private PasswordField oldPasswordField;
|
|
|
|
|
@FXML private PasswordField newPasswordField;
|
|
|
|
|
@FXML private PasswordField confirmNewPasswordField;
|
|
|
|
|
@FXML private Button confirmChangePasswordButton;
|
|
|
|
|
@FXML private Button cancelChangePasswordButton;
|
|
|
|
|
@FXML private Label changePasswordStatusLabel;
|
|
|
|
|
|
|
|
|
|
// 添加修改密码按钮引用
|
|
|
|
|
@FXML private Button changePasswordButton;
|
|
|
|
|
// 数据成员
|
|
|
|
|
private Account currentAccount;
|
|
|
|
|
private List<Question> examQuestions;
|
|
|
|
|
@ -75,11 +92,17 @@ public class ExamController {
|
|
|
|
|
if (registerPanel != null) {
|
|
|
|
|
registerPanel.setVisible(false);
|
|
|
|
|
}
|
|
|
|
|
if (setPasswordPanel != null) {
|
|
|
|
|
setPasswordPanel.setVisible(false);
|
|
|
|
|
}
|
|
|
|
|
if (changePasswordPanel != null) {
|
|
|
|
|
changePasswordPanel.setVisible(false);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
// 添加内部类用于存储注册信息
|
|
|
|
|
static class RegisterInfo {
|
|
|
|
|
final String username;
|
|
|
|
|
final String password;
|
|
|
|
|
String password;
|
|
|
|
|
final String email;
|
|
|
|
|
final String registerCode;
|
|
|
|
|
final Instant expireTime;
|
|
|
|
|
@ -102,12 +125,12 @@ public class ExamController {
|
|
|
|
|
// 添加注册相关方法
|
|
|
|
|
@FXML
|
|
|
|
|
private void handleRegister() {
|
|
|
|
|
|
|
|
|
|
String username = registerUsernameField.getText().trim();
|
|
|
|
|
String password = registerPasswordField.getText();
|
|
|
|
|
String email = registerEmailField.getText().trim();
|
|
|
|
|
|
|
|
|
|
if (username.isEmpty() || password.isEmpty() || email.isEmpty()) {
|
|
|
|
|
registerStatusLabel.setText("请填写所有字段");
|
|
|
|
|
if (username.isEmpty() || email.isEmpty()) {
|
|
|
|
|
registerStatusLabel.setText("请填写用户名和邮箱");
|
|
|
|
|
registerStatusLabel.setStyle("-fx-text-fill: red;");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
@ -119,14 +142,9 @@ public class ExamController {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
// 使用现有的邮箱验证码服务发送注册验证码
|
|
|
|
|
// 发送注册验证码
|
|
|
|
|
emailCodeService.sendCode(email);
|
|
|
|
|
|
|
|
|
|
// 生成注册码并存储待验证信息
|
|
|
|
|
String registerCode = String.valueOf(100000 + new Random().nextInt(900000));
|
|
|
|
|
pendingRegistrations.put(email, new RegisterInfo(username, password, email, registerCode));
|
|
|
|
|
|
|
|
|
|
registerStatusLabel.setText("注册验证码已发送到邮箱,请查收");
|
|
|
|
|
registerStatusLabel.setText("验证码已发送到邮箱,请查收");
|
|
|
|
|
registerStatusLabel.setStyle("-fx-text-fill: green;");
|
|
|
|
|
} catch (Exception e) {
|
|
|
|
|
registerStatusLabel.setText("发送验证码失败:" + e.getMessage());
|
|
|
|
|
@ -149,25 +167,12 @@ private void handleVerifyRegisterCode() {
|
|
|
|
|
boolean isValid = emailCodeService.verifyCode(email, code);
|
|
|
|
|
|
|
|
|
|
if (isValid) {
|
|
|
|
|
// 验证通过,完成注册
|
|
|
|
|
RegisterInfo registerInfo = pendingRegistrations.get(email);
|
|
|
|
|
if (registerInfo != null) {
|
|
|
|
|
Level defaultLevel = Level.小学;
|
|
|
|
|
userMap.put(registerInfo.username, new Account(registerInfo.username, registerInfo.password, defaultLevel));
|
|
|
|
|
pendingRegistrations.remove(email); // 移除已注册的信息
|
|
|
|
|
|
|
|
|
|
registerStatusLabel.setText("注册成功!可以使用新账号登录");
|
|
|
|
|
registerStatusLabel.setText("验证码验证成功,请设置密码");
|
|
|
|
|
registerStatusLabel.setStyle("-fx-text-fill: green;");
|
|
|
|
|
|
|
|
|
|
// 清空注册面板
|
|
|
|
|
registerUsernameField.clear();
|
|
|
|
|
registerPasswordField.clear();
|
|
|
|
|
registerEmailField.clear();
|
|
|
|
|
registerCodeField.clear();
|
|
|
|
|
registerPanel.setVisible(false);
|
|
|
|
|
} else {
|
|
|
|
|
registerStatusLabel.setText("注册信息已过期,请重新注册");
|
|
|
|
|
registerStatusLabel.setStyle("-fx-text-fill: red;");
|
|
|
|
|
// 显示设置密码面板
|
|
|
|
|
if (setPasswordPanel != null) {
|
|
|
|
|
setPasswordPanel.setVisible(true);
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
registerStatusLabel.setText("验证码错误或已过期");
|
|
|
|
|
@ -185,9 +190,257 @@ private void handleVerifyRegisterCode() {
|
|
|
|
|
|
|
|
|
|
@FXML
|
|
|
|
|
private void hideRegisterPanel() {
|
|
|
|
|
// 隐藏注册面板
|
|
|
|
|
if (registerPanel != null) {
|
|
|
|
|
registerPanel.setVisible(false);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 显示登录面板相关组件
|
|
|
|
|
if (usernameField != null) usernameField.setVisible(true);
|
|
|
|
|
if (passwordField != null) passwordField.setVisible(true);
|
|
|
|
|
if (emailField != null) emailField.setVisible(true);
|
|
|
|
|
if (emailCodeField != null) emailCodeField.setVisible(true);
|
|
|
|
|
if (sendCodeButton != null) sendCodeButton.setVisible(true);
|
|
|
|
|
if (verifyCodeButton != null) verifyCodeButton.setVisible(true);
|
|
|
|
|
if (loginButton != null) loginButton.setVisible(true);
|
|
|
|
|
if (emailStatusLabel != null) emailStatusLabel.setVisible(true);
|
|
|
|
|
if (loginStatusLabel != null) loginStatusLabel.setVisible(true);
|
|
|
|
|
|
|
|
|
|
// 清空注册相关字段
|
|
|
|
|
if (registerUsernameField != null) registerUsernameField.clear();
|
|
|
|
|
if (registerEmailField != null) registerEmailField.clear();
|
|
|
|
|
if (registerCodeField != null) registerCodeField.clear();
|
|
|
|
|
if (registerStatusLabel != null) registerStatusLabel.setText("");
|
|
|
|
|
}
|
|
|
|
|
@FXML
|
|
|
|
|
private void showSetPasswordPanel() {
|
|
|
|
|
if (setPasswordPanel != null) {
|
|
|
|
|
setPasswordPanel.setVisible(true);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 隐藏设置密码面板
|
|
|
|
|
*/
|
|
|
|
|
@FXML
|
|
|
|
|
private void hideSetPasswordPanel() {
|
|
|
|
|
if (setPasswordPanel != null) {
|
|
|
|
|
setPasswordPanel.setVisible(false);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 确认设置密码
|
|
|
|
|
*/
|
|
|
|
|
@FXML
|
|
|
|
|
private void handleSetPassword() {
|
|
|
|
|
String password = setPasswordField.getText();
|
|
|
|
|
String confirmPassword = confirmPasswordField.getText();
|
|
|
|
|
|
|
|
|
|
if (password.isEmpty() || confirmPassword.isEmpty()) {
|
|
|
|
|
setPasswordStatusLabel.setText("请输入密码");
|
|
|
|
|
setPasswordStatusLabel.setStyle("-fx-text-fill: red;");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!password.equals(confirmPassword)) {
|
|
|
|
|
setPasswordStatusLabel.setText("两次输入的密码不一致");
|
|
|
|
|
setPasswordStatusLabel.setStyle("-fx-text-fill: red;");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!isValidPassword(password)) {
|
|
|
|
|
setPasswordStatusLabel.setText("密码必须为6-10位,包含大小写字母和数字");
|
|
|
|
|
setPasswordStatusLabel.setStyle("-fx-text-fill: red;");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 获取邮箱(从注册邮箱字段)
|
|
|
|
|
String email = registerEmailField.getText().trim();
|
|
|
|
|
RegisterInfo registerInfo = pendingRegistrations.get(email);
|
|
|
|
|
|
|
|
|
|
if (registerInfo != null) {
|
|
|
|
|
// 更新注册信息中的密码
|
|
|
|
|
registerInfo.password = password;
|
|
|
|
|
|
|
|
|
|
// 完成注册
|
|
|
|
|
userMap.put(registerInfo.username, new Account(registerInfo.username, password, Level.小学));
|
|
|
|
|
pendingRegistrations.remove(email);
|
|
|
|
|
|
|
|
|
|
setPasswordStatusLabel.setText("注册成功!可以使用新账号登录");
|
|
|
|
|
setPasswordStatusLabel.setStyle("-fx-text-fill: green;");
|
|
|
|
|
|
|
|
|
|
// 清空所有注册相关输入框
|
|
|
|
|
registerUsernameField.clear();
|
|
|
|
|
registerEmailField.clear();
|
|
|
|
|
registerCodeField.clear();
|
|
|
|
|
setPasswordField.clear();
|
|
|
|
|
confirmPasswordField.clear();
|
|
|
|
|
|
|
|
|
|
// 隐藏面板
|
|
|
|
|
if (setPasswordPanel != null) {
|
|
|
|
|
setPasswordPanel.setVisible(false);
|
|
|
|
|
}
|
|
|
|
|
if (registerPanel != null) {
|
|
|
|
|
registerPanel.setVisible(false);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 显示登录面板
|
|
|
|
|
hideRegisterPanel();
|
|
|
|
|
} else {
|
|
|
|
|
setPasswordStatusLabel.setText("注册信息丢失,请重新注册");
|
|
|
|
|
setPasswordStatusLabel.setStyle("-fx-text-fill: red;");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 添加注册按钮事件处理方法
|
|
|
|
|
@FXML
|
|
|
|
|
private void handleRegisterUser() {
|
|
|
|
|
String username = registerUsernameField.getText().trim();
|
|
|
|
|
String email = registerEmailField.getText().trim();
|
|
|
|
|
|
|
|
|
|
if (username.isEmpty() || email.isEmpty()) {
|
|
|
|
|
registerStatusLabel.setText("请填写用户名和邮箱");
|
|
|
|
|
registerStatusLabel.setStyle("-fx-text-fill: red;");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (userMap.containsKey(username)) {
|
|
|
|
|
registerStatusLabel.setText("用户名已存在");
|
|
|
|
|
registerStatusLabel.setStyle("-fx-text-fill: red;");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
// 发送注册验证码
|
|
|
|
|
emailCodeService.sendCode(email);
|
|
|
|
|
|
|
|
|
|
// 生成临时注册信息(密码将在后续设置)
|
|
|
|
|
String tempPassword = ""; // 临时空密码
|
|
|
|
|
RegisterInfo registerInfo = new RegisterInfo(username, tempPassword, email, "");
|
|
|
|
|
pendingRegistrations.put(email, registerInfo);
|
|
|
|
|
|
|
|
|
|
registerStatusLabel.setText("注册验证码已发送到邮箱,请查收");
|
|
|
|
|
registerStatusLabel.setStyle("-fx-text-fill: green;");
|
|
|
|
|
} catch (Exception e) {
|
|
|
|
|
registerStatusLabel.setText("发送验证码失败:" + e.getMessage());
|
|
|
|
|
registerStatusLabel.setStyle("-fx-text-fill: red;");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 显示修改密码面板
|
|
|
|
|
*/
|
|
|
|
|
@FXML
|
|
|
|
|
private void showChangePasswordPanel() {
|
|
|
|
|
if (changePasswordPanel != null && currentAccount != null) {
|
|
|
|
|
changePasswordPanel.setVisible(true);
|
|
|
|
|
changePasswordPanel.toFront();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 隐藏修改密码面板
|
|
|
|
|
*/
|
|
|
|
|
@FXML
|
|
|
|
|
private void hideChangePasswordPanel() {
|
|
|
|
|
if (changePasswordPanel != null) {
|
|
|
|
|
changePasswordPanel.setVisible(false);
|
|
|
|
|
// 清空输入框
|
|
|
|
|
oldPasswordField.clear();
|
|
|
|
|
newPasswordField.clear();
|
|
|
|
|
confirmNewPasswordField.clear();
|
|
|
|
|
changePasswordStatusLabel.setText("");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 确认修改密码
|
|
|
|
|
*/
|
|
|
|
|
@FXML
|
|
|
|
|
private void handleChangePassword() {
|
|
|
|
|
if (currentAccount == null) {
|
|
|
|
|
changePasswordStatusLabel.setText("请先登录");
|
|
|
|
|
changePasswordStatusLabel.setStyle("-fx-text-fill: red;");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
String oldPassword = oldPasswordField.getText();
|
|
|
|
|
String newPassword = newPasswordField.getText();
|
|
|
|
|
String confirmNewPassword = confirmNewPasswordField.getText();
|
|
|
|
|
|
|
|
|
|
if (oldPassword.isEmpty() || newPassword.isEmpty() || confirmNewPassword.isEmpty()) {
|
|
|
|
|
changePasswordStatusLabel.setText("请填写所有字段");
|
|
|
|
|
changePasswordStatusLabel.setStyle("-fx-text-fill: red;");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 验证原密码
|
|
|
|
|
if (!currentAccount.password.equals(oldPassword)) {
|
|
|
|
|
changePasswordStatusLabel.setText("原密码错误");
|
|
|
|
|
changePasswordStatusLabel.setStyle("-fx-text-fill: red;");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 验证新密码一致性
|
|
|
|
|
if (!newPassword.equals(confirmNewPassword)) {
|
|
|
|
|
changePasswordStatusLabel.setText("新密码两次输入不一致");
|
|
|
|
|
changePasswordStatusLabel.setStyle("-fx-text-fill: red;");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 验证新密码强度
|
|
|
|
|
if (!isValidPassword(newPassword)) {
|
|
|
|
|
changePasswordStatusLabel.setText("新密码必须为6-10位,包含大小写字母和数字");
|
|
|
|
|
changePasswordStatusLabel.setStyle("-fx-text-fill: red;");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 更新密码
|
|
|
|
|
Account account = userMap.get(currentAccount.username);
|
|
|
|
|
if (account != null) {
|
|
|
|
|
account.password = newPassword; // 注意:需要修改Account类使password可修改
|
|
|
|
|
currentAccount.password = newPassword;
|
|
|
|
|
changePasswordStatusLabel.setText("密码修改成功");
|
|
|
|
|
changePasswordStatusLabel.setStyle("-fx-text-fill: green;");
|
|
|
|
|
|
|
|
|
|
// 清空输入框
|
|
|
|
|
oldPasswordField.clear();
|
|
|
|
|
newPasswordField.clear();
|
|
|
|
|
confirmNewPasswordField.clear();
|
|
|
|
|
|
|
|
|
|
// 隐藏面板
|
|
|
|
|
hideChangePasswordPanel();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 验证密码强度
|
|
|
|
|
* @param password 密码
|
|
|
|
|
* @return 是否符合要求
|
|
|
|
|
*/
|
|
|
|
|
private boolean isValidPassword(String password) {
|
|
|
|
|
// 长度检查
|
|
|
|
|
if (password.length() < 6 || password.length() > 10) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 检查是否包含大小写字母和数字
|
|
|
|
|
boolean hasUpper = false;
|
|
|
|
|
boolean hasLower = false;
|
|
|
|
|
boolean hasDigit = false;
|
|
|
|
|
|
|
|
|
|
for (char c : password.toCharArray()) {
|
|
|
|
|
if (Character.isUpperCase(c)) {
|
|
|
|
|
hasUpper = true;
|
|
|
|
|
} else if (Character.isLowerCase(c)) {
|
|
|
|
|
hasLower = true;
|
|
|
|
|
} else if (Character.isDigit(c)) {
|
|
|
|
|
hasDigit = true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return hasUpper && hasLower && hasDigit;
|
|
|
|
|
}
|
|
|
|
|
private void initAccounts() {
|
|
|
|
|
// 小学三个账号
|
|
|
|
|
@ -278,11 +531,7 @@ private void handleVerifyRegisterCode() {
|
|
|
|
|
String selectedLevel = levelComboBox.getValue();
|
|
|
|
|
ChoiceQuestionGenerator.Level level = ChoiceQuestionGenerator.Level.valueOf(selectedLevel);
|
|
|
|
|
|
|
|
|
|
if (!emailVerified) {
|
|
|
|
|
statusLabel.setText("请先完成邮箱验证码验证");
|
|
|
|
|
statusLabel.setStyle("-fx-text-fill: red;");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 生成考试题目
|
|
|
|
|
questionGenerator = new ChoiceQuestionGenerator();
|
|
|
|
|
@ -327,6 +576,7 @@ private void handleVerifyRegisterCode() {
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 修正 handleVerifyEmailCode 方法,应该用于登录前的邮箱验证而不是注册
|
|
|
|
|
@FXML
|
|
|
|
|
private void handleVerifyEmailCode() {
|
|
|
|
|
String email = emailField != null ? emailField.getText().trim() : "";
|
|
|
|
|
@ -354,6 +604,7 @@ private void handleVerifyRegisterCode() {
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private void startExam() {
|
|
|
|
|
try {
|
|
|
|
|
// 打开专门的考试界面
|
|
|
|
|
@ -385,7 +636,7 @@ private void handleVerifyRegisterCode() {
|
|
|
|
|
// 内部类
|
|
|
|
|
static class Account {
|
|
|
|
|
final String username;
|
|
|
|
|
final String password;
|
|
|
|
|
String password;
|
|
|
|
|
final Level level;
|
|
|
|
|
|
|
|
|
|
Account(String username, String password, Level level) {
|
|
|
|
|
|