You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
307 lines
11 KiB
307 lines
11 KiB
package com.example.mathsystemtogether;
|
|
|
|
import javafx.fxml.FXML;
|
|
import javafx.fxml.FXMLLoader;
|
|
import javafx.scene.Scene;
|
|
import javafx.scene.control.*;
|
|
import javafx.scene.layout.VBox;
|
|
import javafx.stage.Stage;
|
|
import javafx.collections.FXCollections;
|
|
import javafx.collections.ObservableList;
|
|
import java.util.*;
|
|
import java.io.*;
|
|
import java.nio.file.Files;
|
|
import java.nio.file.Paths;
|
|
|
|
/**
|
|
* 考试系统控制器
|
|
*/
|
|
public class ExamController {
|
|
|
|
// 登录界面控件
|
|
@FXML private TextField usernameField;
|
|
@FXML private PasswordField passwordField;
|
|
@FXML private Button loginButton;
|
|
@FXML private Button registerButton;
|
|
@FXML private Label loginStatusLabel;
|
|
|
|
// 考试设置界面控件
|
|
@FXML private VBox examSetupPanel;
|
|
@FXML private Label welcomeLabel;
|
|
@FXML private ComboBox<String> levelComboBox;
|
|
@FXML private TextField questionCountField;
|
|
@FXML private Button startExamButton;
|
|
@FXML private Button logoutButton;
|
|
@FXML private Label statusLabel;
|
|
@FXML private Button changePasswordButton;
|
|
|
|
// 数据成员
|
|
private Account currentAccount;
|
|
private List<Question> examQuestions;
|
|
private ChoiceQuestionGenerator questionGenerator;
|
|
private final Map<String, Account> userMap = new HashMap<>();
|
|
private static final String USER_DATA_FILE = "user_data.txt";
|
|
|
|
// 常量定义
|
|
private static final int MIN_QUESTIONS = 5;
|
|
private static final int MAX_QUESTIONS = 20;
|
|
|
|
@FXML
|
|
public void initialize() {
|
|
initAccounts();
|
|
loadUserDataFromFile();
|
|
setupLevelComboBox();
|
|
examSetupPanel.setVisible(false);
|
|
questionCountField.setText("10");
|
|
}
|
|
|
|
private void initAccounts() {
|
|
// 小学三个账号
|
|
userMap.put("张三1", new Account("张三1", "123", Level.小学));
|
|
userMap.put("张三2", new Account("张三2", "123", Level.小学));
|
|
userMap.put("张三3", new Account("张三3", "123", Level.小学));
|
|
// 初中三个账号
|
|
userMap.put("李四1", new Account("李四1", "123", Level.初中));
|
|
userMap.put("李四2", new Account("李四2", "123", Level.初中));
|
|
userMap.put("李四3", new Account("李四3", "123", Level.初中));
|
|
// 高中三个账号
|
|
userMap.put("王五1", new Account("王五1", "123", Level.高中));
|
|
userMap.put("王五2", new Account("王五2", "123", Level.高中));
|
|
userMap.put("王五3", new Account("王五3", "123", Level.高中));
|
|
}
|
|
|
|
private void setupLevelComboBox() {
|
|
ObservableList<String> levels = FXCollections.observableArrayList("小学", "初中", "高中");
|
|
levelComboBox.setItems(levels);
|
|
levelComboBox.setValue("小学");
|
|
}
|
|
|
|
private void loadUserDataFromFile() {
|
|
try {
|
|
if (!Files.exists(Paths.get(USER_DATA_FILE))) {
|
|
return;
|
|
}
|
|
|
|
List<String> lines = Files.readAllLines(Paths.get(USER_DATA_FILE));
|
|
for (String line : lines) {
|
|
String[] parts = line.split("\\|");
|
|
if (parts.length >= 4) {
|
|
String username = parts[0];
|
|
String password = parts[1];
|
|
String levelStr = parts[3];
|
|
|
|
Level level;
|
|
try {
|
|
level = Level.valueOf(levelStr);
|
|
} catch (IllegalArgumentException e) {
|
|
level = Level.小学; // 默认级别
|
|
}
|
|
|
|
userMap.put(username, new Account(username, password, level));
|
|
}
|
|
}
|
|
} catch (IOException e) {
|
|
// 加载用户数据失败,静默处理
|
|
}
|
|
}
|
|
|
|
@FXML
|
|
private void handleLogin() {
|
|
String username = usernameField.getText().trim();
|
|
String password = passwordField.getText();
|
|
|
|
if (username.isEmpty() || password.isEmpty()) {
|
|
loginStatusLabel.setText("请输入用户名和密码");
|
|
loginStatusLabel.setStyle("-fx-text-fill: red;");
|
|
return;
|
|
}
|
|
|
|
Account account = userMap.get(username);
|
|
if (account != null && account.password.equals(password)) {
|
|
currentAccount = account;
|
|
welcomeLabel.setText("欢迎," + username + "!当前级别:" + account.level);
|
|
levelComboBox.setValue(account.level.toString());
|
|
examSetupPanel.setVisible(true);
|
|
loginStatusLabel.setText("登录成功!");
|
|
loginStatusLabel.setStyle("-fx-text-fill: green;");
|
|
} else {
|
|
loginStatusLabel.setText("用户名或密码错误");
|
|
loginStatusLabel.setStyle("-fx-text-fill: red;");
|
|
}
|
|
}
|
|
|
|
@FXML
|
|
private void handleRegister() {
|
|
try {
|
|
// 打开注册界面
|
|
FXMLLoader loader = new FXMLLoader(getClass().getResource("register-view.fxml"));
|
|
Scene scene = new Scene(loader.load(), 800, 800);
|
|
Stage registerStage = new Stage();
|
|
registerStage.setTitle("数学考试系统 - 用户注册");
|
|
registerStage.setScene(scene);
|
|
registerStage.setResizable(false);
|
|
|
|
// 获取注册控制器并设置原始登录界面引用
|
|
RegisterController registerController = loader.getController();
|
|
Stage currentStage = (Stage) loginStatusLabel.getScene().getWindow();
|
|
registerController.setOriginalLoginStage(currentStage);
|
|
|
|
registerStage.show();
|
|
|
|
} catch (Exception e) {
|
|
loginStatusLabel.setText("打开注册界面失败:" + e.getMessage());
|
|
loginStatusLabel.setStyle("-fx-text-fill: red;");
|
|
}
|
|
}
|
|
|
|
@FXML
|
|
private void handleLogout() {
|
|
currentAccount = null;
|
|
examQuestions = null;
|
|
examSetupPanel.setVisible(false);
|
|
usernameField.clear();
|
|
passwordField.clear();
|
|
loginStatusLabel.setText("");
|
|
statusLabel.setText("");
|
|
}
|
|
|
|
@FXML
|
|
private void handleStartExam() {
|
|
if (currentAccount == null) {
|
|
statusLabel.setText("请先登录");
|
|
statusLabel.setStyle("-fx-text-fill: red;");
|
|
return;
|
|
}
|
|
|
|
try {
|
|
int count = Integer.parseInt(questionCountField.getText());
|
|
if (count < MIN_QUESTIONS || count > MAX_QUESTIONS) {
|
|
statusLabel.setText("题目数量应在" + MIN_QUESTIONS + "-" + MAX_QUESTIONS + "之间");
|
|
statusLabel.setStyle("-fx-text-fill: red;");
|
|
return;
|
|
}
|
|
|
|
// 获取选择的级别
|
|
String selectedLevel = levelComboBox.getValue();
|
|
ChoiceQuestionGenerator.Level level = ChoiceQuestionGenerator.Level.valueOf(selectedLevel);
|
|
|
|
// 生成考试题目
|
|
questionGenerator = new ChoiceQuestionGenerator();
|
|
examQuestions = questionGenerator.generateQuestions(level, count);
|
|
|
|
if (examQuestions.isEmpty()) {
|
|
statusLabel.setText("无法生成题目,请重试");
|
|
statusLabel.setStyle("-fx-text-fill: red;");
|
|
return;
|
|
}
|
|
|
|
// 开始考试
|
|
startExam();
|
|
|
|
} catch (NumberFormatException e) {
|
|
statusLabel.setText("请输入有效的数字");
|
|
statusLabel.setStyle("-fx-text-fill: red;");
|
|
}
|
|
}
|
|
|
|
@FXML
|
|
private void handleChangePassword() {
|
|
if (currentAccount == null) {
|
|
statusLabel.setText("请先登录");
|
|
statusLabel.setStyle("-fx-text-fill: red;");
|
|
return;
|
|
}
|
|
|
|
try {
|
|
FXMLLoader loader = new FXMLLoader(getClass().getResource("change-password-view.fxml"));
|
|
Scene scene = new Scene(loader.load(), 600, 500);
|
|
Stage changePasswordStage = new Stage();
|
|
changePasswordStage.setTitle("修改密码");
|
|
changePasswordStage.setScene(scene);
|
|
changePasswordStage.setResizable(false);
|
|
|
|
// 传递当前用户信息给密码修改控制器
|
|
ChangePasswordController controller = loader.getController();
|
|
controller.setCurrentUser(currentAccount.username);
|
|
controller.setExamController(this);
|
|
|
|
changePasswordStage.show();
|
|
} catch (Exception e) {
|
|
statusLabel.setText("打开修改密码界面失败:" + e.getMessage());
|
|
statusLabel.setStyle("-fx-text-fill: red;");
|
|
}
|
|
}
|
|
|
|
// 供 ChangePasswordController 调用的方法
|
|
public boolean checkUserPassword(String username, String password) {
|
|
Account account = userMap.get(username);
|
|
return account != null && account.password.equals(password);
|
|
}
|
|
|
|
// 更新用户密码
|
|
public void updateUserPassword(String username, String newPassword) {
|
|
Account account = userMap.get(username);
|
|
if (account != null) {
|
|
account.password = newPassword;
|
|
}
|
|
}
|
|
|
|
// 为继续做题设置用户信息
|
|
public void setUserForContinueExam(String username, String level) {
|
|
// 设置当前用户
|
|
Account account = userMap.get(username);
|
|
if (account != null) {
|
|
currentAccount = account;
|
|
welcomeLabel.setText("欢迎," + username + "!当前级别:" + account.level);
|
|
levelComboBox.setValue(account.level.toString());
|
|
examSetupPanel.setVisible(true);
|
|
loginStatusLabel.setText("继续做题模式");
|
|
loginStatusLabel.setStyle("-fx-text-fill: green;");
|
|
}
|
|
}
|
|
|
|
private void startExam() {
|
|
try {
|
|
// 打开专门的考试界面
|
|
FXMLLoader loader = new FXMLLoader(getClass().getResource("exam-taking-view.fxml"));
|
|
Scene scene = new Scene(loader.load(), 1000, 950);
|
|
Stage examStage = new Stage();
|
|
examStage.setTitle("数学考试 - " + currentAccount.username);
|
|
examStage.setScene(scene);
|
|
examStage.setResizable(false);
|
|
|
|
// 设置考试数据
|
|
ExamTakingController examController = loader.getController();
|
|
examController.setExamData(examQuestions, currentAccount.username, levelComboBox.getValue());
|
|
|
|
// 显示考试窗口
|
|
examStage.show();
|
|
|
|
// 隐藏主窗口
|
|
Stage mainStage = (Stage) startExamButton.getScene().getWindow();
|
|
mainStage.hide();
|
|
|
|
} catch (Exception e) {
|
|
statusLabel.setText("启动考试失败:" + e.getMessage());
|
|
statusLabel.setStyle("-fx-text-fill: red;");
|
|
}
|
|
}
|
|
|
|
// 内部类
|
|
static class Account {
|
|
final String username;
|
|
String password;
|
|
final Level level;
|
|
|
|
Account(String username, String password, Level level) {
|
|
this.username = username;
|
|
this.password = password;
|
|
this.level = level;
|
|
}
|
|
}
|
|
|
|
enum Level {
|
|
小学, 初中, 高中
|
|
}
|
|
}
|