Compare commits

..

No commits in common. 'main' and 'develop2' have entirely different histories.

@ -1,19 +0,0 @@
<component name="ArtifactManager">
<artifact type="jar" name="MathSystemTogether:jar">
<output-path>$PROJECT_DIR$/out/artifacts/MathSystemTogether_jar</output-path>
<root id="archive" name="MathSystemTogether.jar">
<element id="module-output" name="MathSystemTogether" />
<element id="extracted-dir" path="D:/apache-maven-3.9.9/repository/org/openjfx/javafx-base/21/javafx-base-21.jar" path-in-jar="/" />
<element id="extracted-dir" path="D:/apache-maven-3.9.9/repository/org/openjfx/javafx-graphics/21/javafx-graphics-21.jar" path-in-jar="/" />
<element id="extracted-dir" path="D:/apache-maven-3.9.9/repository/org/openjfx/javafx-fxml/21/javafx-fxml-21-win.jar" path-in-jar="/" />
<element id="extracted-dir" path="D:/apache-maven-3.9.9/repository/jakarta/activation/jakarta.activation-api/2.1.3/jakarta.activation-api-2.1.3.jar" path-in-jar="/" />
<element id="extracted-dir" path="D:/apache-maven-3.9.9/repository/org/openjfx/javafx-graphics/21/javafx-graphics-21-win.jar" path-in-jar="/" />
<element id="extracted-dir" path="D:/apache-maven-3.9.9/repository/org/openjfx/javafx-controls/21/javafx-controls-21-win.jar" path-in-jar="/" />
<element id="extracted-dir" path="D:/apache-maven-3.9.9/repository/org/openjfx/javafx-base/21/javafx-base-21-win.jar" path-in-jar="/" />
<element id="extracted-dir" path="D:/apache-maven-3.9.9/repository/com/sun/activation/jakarta.activation/2.0.1/jakarta.activation-2.0.1.jar" path-in-jar="/" />
<element id="extracted-dir" path="D:/apache-maven-3.9.9/repository/org/openjfx/javafx-controls/21/javafx-controls-21.jar" path-in-jar="/" />
<element id="extracted-dir" path="D:/apache-maven-3.9.9/repository/org/openjfx/javafx-fxml/21/javafx-fxml-21.jar" path-in-jar="/" />
<element id="extracted-dir" path="D:/apache-maven-3.9.9/repository/com/sun/mail/jakarta.mail/2.0.1/jakarta.mail-2.0.1.jar" path-in-jar="/" />
</root>
</artifact>
</component>

@ -1,164 +1,149 @@
package com.example.mathsystemtogether;
import javafx.fxml.FXML;
import javafx.scene.control.*;
import javafx.stage.Stage;
import java.io.*;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.List;
import java.util.regex.Pattern;
public class ChangePasswordController {
@FXML
private TextField usernameField;
@FXML
private PasswordField oldPasswordField;
@FXML
private PasswordField newPasswordField;
@FXML
private PasswordField confirmNewPasswordField;
@FXML
private Button changePasswordButton;
@FXML
private Button cancelButton;
@FXML
private Label statusLabel;
private String currentUser;
private ExamController examController;
private static final String USER_DATA_FILE = "user_data.txt";
// 密码强度验证正则表达式
private static final String PASSWORD_REGEX = "^(?=.*[a-z])(?=.*[A-Z])(?=.*\\d).+$";
private static final Pattern PASSWORD_PATTERN = Pattern.compile(PASSWORD_REGEX);
public void setCurrentUser(String username) {
this.currentUser = username;
usernameField.setText(username);
}
public void setExamController(ExamController examController) {
this.examController = examController;
}
@FXML
private void handleChangePassword() {
String oldPassword = oldPasswordField.getText();
String newPassword = newPasswordField.getText();
String confirmNewPassword = confirmNewPasswordField.getText();
if (oldPassword.isEmpty() || newPassword.isEmpty() || confirmNewPassword.isEmpty()) {
showStatus("请填写所有字段", true);
return;
}
if (!examController.checkUserPassword(currentUser, oldPassword)) {
showStatus("原密码错误", true);
return;
}
if (newPassword.length() < 6) {
showStatus("新密码至少需要6个字符", true);
return;
}
if (!isValidPassword(newPassword)) {
showStatus("新密码必须包含大小写字母和数字", true);
return;
}
if (!newPassword.equals(confirmNewPassword)) {
showStatus("两次输入的新密码不一致", true);
return;
}
if (oldPassword.equals(newPassword)) {
showStatus("新密码不能与原密码相同", true);
return;
}
if (updatePassword(currentUser, newPassword)) {
showStatus("密码修改成功!", false);
// 延迟关闭窗口
new java.util.Timer().schedule(
new java.util.TimerTask() {
@Override
public void run() {
javafx.application.Platform.runLater(() -> {
handleClose();
});
}
},
1500
);
} else {
showStatus("密码修改失败,请重试", true);
}
}
@FXML
private void handleCancel() {
handleClose();
}
private void handleClose() {
Stage stage = (Stage) cancelButton.getScene().getWindow();
stage.close();
}
private boolean updatePassword(String username, String newPassword) {
try {
// 读取所有用户数据
List<String> lines = Files.readAllLines(Paths.get(USER_DATA_FILE));
boolean userFound = false;
for (int i = 0; i < lines.size(); i++) {
String[] parts = lines.get(i).split("\\|");
if (parts.length >= 2 && parts[0].equals(username)) {
// 更新密码
parts[1] = newPassword;
lines.set(i, String.join("|", parts));
userFound = true;
break;
}
}
if (userFound) {
// 写回文件
Files.write(Paths.get(USER_DATA_FILE), lines);
// 更新内存中的用户数据
examController.updateUserPassword(username, newPassword);
return true;
}
} catch (IOException e) {
e.printStackTrace();
}
return false;
}
/**
*
*
*/
private boolean isValidPassword(String password) {
return PASSWORD_PATTERN.matcher(password).matches();
}
private void showStatus(String message, boolean isError) {
statusLabel.setText(message);
if (isError) {
statusLabel.setStyle("-fx-text-fill: #DC143C; -fx-font-weight: bold; -fx-font-size: 14;");
} else {
statusLabel.setStyle("-fx-text-fill: #228B22; -fx-font-weight: bold; -fx-font-size: 14;");
}
}
}
package com.example.mathsystemtogether;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.scene.Scene;
import javafx.scene.control.*;
import javafx.stage.Stage;
import java.io.*;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
import java.util.List;
public class ChangePasswordController {
@FXML
private TextField usernameField;
@FXML
private PasswordField oldPasswordField;
@FXML
private PasswordField newPasswordField;
@FXML
private PasswordField confirmNewPasswordField;
@FXML
private Button changePasswordButton;
@FXML
private Button cancelButton;
@FXML
private Label statusLabel;
private String currentUser;
private ExamController examController;
private static final String USER_DATA_FILE = "user_data.txt";
public void setCurrentUser(String username) {
this.currentUser = username;
usernameField.setText(username);
}
public void setExamController(ExamController examController) {
this.examController = examController;
}
@FXML
private void handleChangePassword() {
String oldPassword = oldPasswordField.getText();
String newPassword = newPasswordField.getText();
String confirmNewPassword = confirmNewPasswordField.getText();
if (oldPassword.isEmpty() || newPassword.isEmpty() || confirmNewPassword.isEmpty()) {
showStatus("请填写所有字段", true);
return;
}
if (!examController.checkUserPassword(currentUser, oldPassword)) {
showStatus("原密码错误", true);
return;
}
if (newPassword.length() < 6) {
showStatus("新密码至少需要6个字符", true);
return;
}
if (!newPassword.equals(confirmNewPassword)) {
showStatus("两次输入的新密码不一致", true);
return;
}
if (oldPassword.equals(newPassword)) {
showStatus("新密码不能与原密码相同", true);
return;
}
if (updatePassword(currentUser, newPassword)) {
showStatus("密码修改成功!", false);
// 延迟关闭窗口
new java.util.Timer().schedule(
new java.util.TimerTask() {
@Override
public void run() {
javafx.application.Platform.runLater(() -> {
handleClose();
});
}
},
1500
);
} else {
showStatus("密码修改失败,请重试", true);
}
}
@FXML
private void handleCancel() {
handleClose();
}
private void handleClose() {
Stage stage = (Stage) cancelButton.getScene().getWindow();
stage.close();
}
private boolean updatePassword(String username, String newPassword) {
try {
// 读取所有用户数据
List<String> lines = Files.readAllLines(Paths.get(USER_DATA_FILE));
boolean userFound = false;
for (int i = 0; i < lines.size(); i++) {
String[] parts = lines.get(i).split("\\|");
if (parts.length >= 2 && parts[0].equals(username)) {
// 更新密码
parts[1] = newPassword;
lines.set(i, String.join("|", parts));
userFound = true;
break;
}
}
if (userFound) {
// 写回文件
Files.write(Paths.get(USER_DATA_FILE), lines);
// 更新内存中的用户数据
examController.updateUserPassword(username, newPassword);
return true;
}
} catch (IOException e) {
e.printStackTrace();
}
return false;
}
private void showStatus(String message, boolean isError) {
statusLabel.setText(message);
if (isError) {
statusLabel.setStyle("-fx-text-fill: #DC143C; -fx-font-weight: bold; -fx-font-size: 14;");
} else {
statusLabel.setStyle("-fx-text-fill: #228B22; -fx-font-weight: bold; -fx-font-size: 14;");
}
}
}

@ -54,13 +54,12 @@ public class ChoiceQuestionGenerator {
*
*/
private Question generatePrimaryQuestion(int questionNumber) {
// 随机选择运算符号数量1-3个
int operatorCount = 1 + random.nextInt(3);
// 生成复合运算表达式
String[] expression = generateCompoundExpression(operatorCount);
String questionText = expression[0];
int correctAnswer = Integer.parseInt(expression[1]);
int a = MIN_OPERAND_VALUE + random.nextInt(MAX_OPERAND_VALUE);
int b = MIN_OPERAND_VALUE + random.nextInt(MAX_OPERAND_VALUE);
String operation = getRandomOperation("+*-");
String questionText = String.format("%d %s %d = ?", a, operation, b);
int correctAnswer = calculate(a, b, operation);
// 生成错误选项
List<Integer> options = generateWrongOptions(correctAnswer);
@ -80,110 +79,48 @@ public class ChoiceQuestionGenerator {
*
*/
private Question generateJuniorQuestion(int questionNumber) {
// 随机选择运算符号数量1-3个
int operatorCount = 1 + random.nextInt(3);
// 30%概率生成纯平方/开方题目70%概率生成包含平方/开方的复合运算题目
if (random.nextDouble() < 0.3) {
return generatePureSquareOrRootQuestion(questionNumber);
} else {
return generateJuniorCompoundQuestion(operatorCount, questionNumber);
}
}
int a = MIN_OPERAND_VALUE + random.nextInt(MAX_OPERAND_VALUE);
/**
*
*/
private Question generatePureSquareOrRootQuestion(int questionNumber) {
// 50%概率生成平方或开方题目
if (random.nextBoolean()) {
return generateSquareQuestion(questionNumber);
// 平方题目
String questionText = String.format("%d² = ?", a);
int correctAnswer = a * a;
List<Integer> options = generateWrongOptions(correctAnswer);
options.add(correctAnswer);
Collections.shuffle(options);
return new Question(questionText,
String.valueOf(options.get(0)),
String.valueOf(options.get(1)),
String.valueOf(options.get(2)),
String.valueOf(options.get(3)),
String.valueOf(correctAnswer),
questionNumber);
} else {
return generateRootQuestion(questionNumber);
}
}
// 开方题目
int perfectSquare = (int) Math.pow(random.nextInt(10) + 1, 2);
String questionText = String.format("√%d = ?", perfectSquare);
int correctAnswer = (int) Math.sqrt(perfectSquare);
List<Integer> options = generateWrongOptions(correctAnswer);
options.add(correctAnswer);
Collections.shuffle(options);
/**
*
*/
private Question generateSquareQuestion(int questionNumber) {
int a = MIN_OPERAND_VALUE + random.nextInt(MAX_OPERAND_VALUE);
String questionText = String.format("%d² = ?", a);
int correctAnswer = a * a;
List<Integer> options = generateWrongOptions(correctAnswer);
options.add(correctAnswer);
Collections.shuffle(options);
return new Question(questionText,
String.valueOf(options.get(0)),
String.valueOf(options.get(1)),
String.valueOf(options.get(2)),
String.valueOf(options.get(3)),
String.valueOf(correctAnswer),
questionNumber);
}
/**
*
*/
private Question generateRootQuestion(int questionNumber) {
int perfectSquare = (int) Math.pow(random.nextInt(10) + 1, 2);
String questionText = String.format("√%d = ?", perfectSquare);
int correctAnswer = (int) Math.sqrt(perfectSquare);
List<Integer> options = generateWrongOptions(correctAnswer);
options.add(correctAnswer);
Collections.shuffle(options);
return new Question(questionText,
String.valueOf(options.get(0)),
String.valueOf(options.get(1)),
String.valueOf(options.get(2)),
String.valueOf(options.get(3)),
String.valueOf(correctAnswer),
questionNumber);
}
/**
*
*/
private Question generateJuniorCompoundQuestion(int operatorCount, int questionNumber) {
// 生成包含平方/开方的复合运算表达式(确保包含平方或开方)
String[] expression = generateJuniorCompoundExpressionWithGuarantee(operatorCount);
String questionText = expression[0];
int correctAnswer = Integer.parseInt(expression[1]);
// 生成错误选项
List<Integer> options = generateWrongOptions(correctAnswer);
options.add(correctAnswer);
Collections.shuffle(options);
return new Question(questionText,
String.valueOf(options.get(0)),
String.valueOf(options.get(1)),
String.valueOf(options.get(2)),
String.valueOf(options.get(3)),
String.valueOf(correctAnswer),
questionNumber);
return new Question(questionText,
String.valueOf(options.get(0)),
String.valueOf(options.get(1)),
String.valueOf(options.get(2)),
String.valueOf(options.get(3)),
String.valueOf(correctAnswer),
questionNumber);
}
}
/**
*
*/
private Question generateSeniorQuestion(int questionNumber) {
// 随机选择运算符号数量1-3个
int operatorCount = 1 + random.nextInt(3);
// 30%概率生成纯三角函数题目70%概率生成包含三角函数的复合运算题目
if (random.nextDouble() < 0.3) {
return generatePureTrigQuestion(questionNumber);
} else {
return generateSeniorCompoundQuestion(operatorCount, questionNumber);
}
}
/**
*
*/
private Question generatePureTrigQuestion(int questionNumber) {
// 使用常见角度: 0°, 30°, 45°, 60°, 90°, 120°, 135°, 150°, 180°, 210°, 225°, 270°, 300°, 315°, 330°
int[] commonAngles = {0, 30, 45, 60, 90, 120, 135, 150, 180, 210, 225, 270, 300, 315, 330};
int angle = commonAngles[random.nextInt(commonAngles.length)];
String[] functions = {"sin", "cos", "tan"};
@ -207,30 +144,7 @@ public class ChoiceQuestionGenerator {
options.get(3),
correctAnswer,
questionNumber);
}
/**
*
*/
private Question generateSeniorCompoundQuestion(int operatorCount, int questionNumber) {
// 生成包含三角函数的复合运算表达式(确保包含三角函数)
String[] expression = generateSeniorCompoundExpressionWithGuarantee(operatorCount);
String questionText = expression[0];
int correctAnswer = Integer.parseInt(expression[1]);
// 生成错误选项
List<Integer> options = generateWrongOptions(correctAnswer);
options.add(correctAnswer);
Collections.shuffle(options);
return new Question(questionText,
String.valueOf(options.get(0)),
String.valueOf(options.get(1)),
String.valueOf(options.get(2)),
String.valueOf(options.get(3)),
String.valueOf(correctAnswer),
questionNumber);
}
}
/**
*
@ -334,90 +248,69 @@ private String generateNearbyValue(double correctAnswer, Set<String> usedOptions
*
*/
private double calculateTrigFunction(String function, int angle) {
double radians = Math.toRadians(angle);
switch (function) {
case "sin":
return calculateSin(angle);
// 对特定角度返回精确值
switch (angle) {
case 0: return 0;
case 30: return 0.5;
case 45: return Math.sqrt(2)/2;
case 60: return Math.sqrt(3)/2;
case 90: return 1;
case 120: return Math.sqrt(3)/2;
case 135: return Math.sqrt(2)/2;
case 150: return 0.5;
case 180: return 0;
case 210: return -0.5;
case 225: return -Math.sqrt(2)/2;
case 270: return -1;
case 300: return -Math.sqrt(3)/2;
case 315: return -Math.sqrt(2)/2;
case 330: return -0.5;
default: return Math.sin(radians);
}
case "cos":
return calculateCos(angle);
// 对特定角度返回精确值
switch (angle) {
case 0: return 1;
case 30: return Math.sqrt(3)/2;
case 45: return Math.sqrt(2)/2;
case 60: return 0.5;
case 90: return 0;
case 120: return -0.5;
case 135: return -Math.sqrt(2)/2;
case 150: return -Math.sqrt(3)/2;
case 180: return -1;
case 210: return -Math.sqrt(3)/2;
case 225: return -Math.sqrt(2)/2;
case 270: return 0;
case 300: return 0.5;
case 315: return Math.sqrt(2)/2;
case 330: return Math.sqrt(3)/2;
default: return Math.cos(radians);
}
case "tan":
return calculateTan(angle);
default:
return 0;
}
}
/**
*
*/
private double calculateSin(int angle) {
switch (angle) {
case 0: return 0;
case 30: return 0.5;
case 45: return Math.sqrt(2)/2;
case 60: return Math.sqrt(3)/2;
case 90: return 1;
case 120: return Math.sqrt(3)/2;
case 135: return Math.sqrt(2)/2;
case 150: return 0.5;
case 180: return 0;
case 210: return -0.5;
case 225: return -Math.sqrt(2)/2;
case 270: return -1;
case 300: return -Math.sqrt(3)/2;
case 315: return -Math.sqrt(2)/2;
case 330: return -0.5;
default:
return Math.sin(Math.toRadians(angle));
}
}
/**
*
*/
private double calculateCos(int angle) {
switch (angle) {
case 0: return 1;
case 30: return Math.sqrt(3)/2;
case 45: return Math.sqrt(2)/2;
case 60: return 0.5;
case 90: return 0;
case 120: return -0.5;
case 135: return -Math.sqrt(2)/2;
case 150: return -Math.sqrt(3)/2;
case 180: return -1;
case 210: return -Math.sqrt(3)/2;
case 225: return -Math.sqrt(2)/2;
case 270: return 0;
case 300: return 0.5;
case 315: return Math.sqrt(2)/2;
case 330: return Math.sqrt(3)/2;
default:
return Math.cos(Math.toRadians(angle));
}
}
/**
*
*/
private double calculateTan(int angle) {
switch (angle) {
case 0: return 0;
case 30: return Math.sqrt(3)/3;
case 45: return 1;
case 60: return Math.sqrt(3);
case 90: return Double.POSITIVE_INFINITY; // 未定义
case 120: return -Math.sqrt(3);
case 135: return -1;
case 150: return -Math.sqrt(3)/3;
case 180: return 0;
case 210: return Math.sqrt(3)/3;
case 225: return 1;
case 270: return Double.POSITIVE_INFINITY; // 未定义
case 300: return -Math.sqrt(3);
case 315: return -1;
case 330: return -Math.sqrt(3)/3;
default:
return Math.tan(Math.toRadians(angle));
// 对特定角度返回精确值或未定义
switch (angle) {
case 0: return 0;
case 30: return Math.sqrt(3)/3;
case 45: return 1;
case 60: return Math.sqrt(3);
case 90: return Double.POSITIVE_INFINITY; // 未定义
case 120: return -Math.sqrt(3);
case 135: return -1;
case 150: return -Math.sqrt(3)/3;
case 180: return 0;
case 210: return Math.sqrt(3)/3;
case 225: return 1;
case 270: return Double.POSITIVE_INFINITY; // 未定义
case 300: return -Math.sqrt(3);
case 315: return -1;
case 330: return -Math.sqrt(3)/3;
default: return Math.tan(radians);
}
default: return 0;
}
}
@ -463,596 +356,6 @@ private double calculateTan(int angle) {
}
/**
*
* @param operatorCount 1-3
* @return [, ]
*/
private String[] generateCompoundExpression(int operatorCount) {
StringBuilder expression = new StringBuilder();
List<Integer> operands = new ArrayList<>();
List<String> operators = new ArrayList<>();
// 生成操作数(运算符数量+1个操作数
for (int i = 0; i <= operatorCount; i++) {
operands.add(MIN_OPERAND_VALUE + random.nextInt(MAX_OPERAND_VALUE));
}
// 生成运算符
String[] availableOps = {"+", "-", "*"};
for (int i = 0; i < operatorCount; i++) {
operators.add(availableOps[random.nextInt(availableOps.length)]);
}
// 构建表达式字符串
expression.append(operands.get(0));
for (int i = 0; i < operatorCount; i++) {
expression.append(" ").append(operators.get(i)).append(" ").append(operands.get(i + 1));
}
expression.append(" = ?");
// 计算表达式结果
int result = calculateCompoundExpression(operands, operators);
return new String[]{expression.toString(), String.valueOf(result)};
}
/**
* /
*/
private String[] generateJuniorCompoundExpressionWithGuarantee(int operatorCount) {
StringBuilder expression = new StringBuilder();
List<Integer> operands = new ArrayList<>();
List<String> operators = new ArrayList<>();
// 生成操作数(运算符数量+1个操作数
for (int i = 0; i <= operatorCount; i++) {
operands.add(MIN_OPERAND_VALUE + random.nextInt(MAX_OPERAND_VALUE));
}
// 确保至少有一个平方或开方运算
boolean hasSquareOrRoot = false;
// 生成运算符
for (int i = 0; i < operatorCount; i++) {
String[] availableOps;
if (!hasSquareOrRoot && i == operatorCount - 1) {
// 最后一个运算符必须是平方或开方
availableOps = new String[]{"²", "√"};
hasSquareOrRoot = true;
} else if (!hasSquareOrRoot && random.nextDouble() < 0.4) {
// 40%概率选择平方或开方
availableOps = new String[]{"+", "-", "*", "/", "²", "√"};
} else {
// 其他情况选择基础运算
availableOps = new String[]{"+", "-", "*", "/"};
}
String selectedOp = availableOps[random.nextInt(availableOps.length)];
if (selectedOp.equals("²") || selectedOp.equals("√")) {
hasSquareOrRoot = true;
}
operators.add(selectedOp);
}
// 构建表达式字符串
expression.append(operands.get(0));
for (int i = 0; i < operatorCount; i++) {
if (operators.get(i).equals("²")) {
expression.append("²");
} else if (operators.get(i).equals("√")) {
// 确保开方的是完全平方数
int perfectSquare = (int) Math.pow(random.nextInt(10) + 1, 2);
expression.append("√").append(perfectSquare);
operands.set(i + 1, (int) Math.sqrt(perfectSquare));
} else {
expression.append(" ").append(operators.get(i)).append(" ").append(operands.get(i + 1));
}
}
expression.append(" = ?");
// 计算表达式结果
int result = calculateJuniorCompoundExpression(operands, operators);
return new String[]{expression.toString(), String.valueOf(result)};
}
/**
* /
*/
private String[] generateJuniorCompoundExpression(int operatorCount) {
StringBuilder expression = new StringBuilder();
List<Integer> operands = new ArrayList<>();
List<String> operators = new ArrayList<>();
// 生成操作数(运算符数量+1个操作数
for (int i = 0; i <= operatorCount; i++) {
operands.add(MIN_OPERAND_VALUE + random.nextInt(MAX_OPERAND_VALUE));
}
// 生成运算符(包含平方/开方)
String[] availableOps = {"+", "-", "*", "/", "²", "√"};
for (int i = 0; i < operatorCount; i++) {
operators.add(availableOps[random.nextInt(availableOps.length)]);
}
// 构建表达式字符串
expression.append(operands.get(0));
for (int i = 0; i < operatorCount; i++) {
if (operators.get(i).equals("²")) {
expression.append("²");
} else if (operators.get(i).equals("√")) {
// 确保开方的是完全平方数
int perfectSquare = (int) Math.pow(random.nextInt(10) + 1, 2);
expression.append("√").append(perfectSquare);
operands.set(i + 1, (int) Math.sqrt(perfectSquare));
} else {
expression.append(" ").append(operators.get(i)).append(" ").append(operands.get(i + 1));
}
}
expression.append(" = ?");
// 计算表达式结果
int result = calculateJuniorCompoundExpression(operands, operators);
return new String[]{expression.toString(), String.valueOf(result)};
}
/**
*
*/
private String[] generateCompoundExpressionWithDivision(int operatorCount) {
StringBuilder expression = new StringBuilder();
List<Integer> operands = new ArrayList<>();
List<String> operators = new ArrayList<>();
// 生成操作数(运算符数量+1个操作数
for (int i = 0; i <= operatorCount; i++) {
operands.add(MIN_OPERAND_VALUE + random.nextInt(MAX_OPERAND_VALUE));
}
// 生成运算符(包含除法)
String[] availableOps = {"+", "-", "*", "/"};
for (int i = 0; i < operatorCount; i++) {
operators.add(availableOps[random.nextInt(availableOps.length)]);
}
// 构建表达式字符串
expression.append(operands.get(0));
for (int i = 0; i < operatorCount; i++) {
expression.append(" ").append(operators.get(i)).append(" ").append(operands.get(i + 1));
}
expression.append(" = ?");
// 计算表达式结果
int result = calculateCompoundExpressionWithDivision(operands, operators);
return new String[]{expression.toString(), String.valueOf(result)};
}
/**
*
*/
private int calculateCompoundExpression(List<Integer> operands, List<String> operators) {
// 先处理乘除法,再处理加减法
List<Integer> numbers = new ArrayList<>(operands);
List<String> ops = new ArrayList<>(operators);
// 第一轮:处理乘除法
for (int i = 0; i < ops.size(); i++) {
if (ops.get(i).equals("*")) {
int result = numbers.get(i) * numbers.get(i + 1);
numbers.set(i, result);
numbers.remove(i + 1);
ops.remove(i);
i--; // 调整索引
}
}
// 第二轮:处理加减法
int result = numbers.get(0);
for (int i = 0; i < ops.size(); i++) {
if (ops.get(i).equals("+")) {
result += numbers.get(i + 1);
} else if (ops.get(i).equals("-")) {
result -= numbers.get(i + 1);
}
}
return result;
}
/**
*
*/
private String[] generateSeniorCompoundExpressionWithGuarantee(int operatorCount) {
StringBuilder expression = new StringBuilder();
List<Double> operands = new ArrayList<>();
List<String> operators = new ArrayList<>();
// 生成操作数(运算符数量+1个操作数
for (int i = 0; i <= operatorCount; i++) {
operands.add((double)(MIN_OPERAND_VALUE + random.nextInt(MAX_OPERAND_VALUE)));
}
// 确保至少有一个三角函数运算
boolean hasTrigFunction = false;
// 生成运算符
for (int i = 0; i < operatorCount; i++) {
String[] availableOps;
if (!hasTrigFunction && i == operatorCount - 1) {
// 最后一个运算符必须是三角函数
availableOps = new String[]{"sin", "cos", "tan"};
hasTrigFunction = true;
} else if (!hasTrigFunction && random.nextDouble() < 0.4) {
// 40%概率选择三角函数
availableOps = new String[]{"+", "-", "*", "/", "sin", "cos", "tan"};
} else {
// 其他情况选择基础运算
availableOps = new String[]{"+", "-", "*", "/"};
}
String selectedOp = availableOps[random.nextInt(availableOps.length)];
if (selectedOp.equals("sin") || selectedOp.equals("cos") || selectedOp.equals("tan")) {
hasTrigFunction = true;
}
operators.add(selectedOp);
}
// 构建表达式字符串
expression.append(operands.get(0).intValue());
for (int i = 0; i < operatorCount; i++) {
if (operators.get(i).equals("sin") || operators.get(i).equals("cos") || operators.get(i).equals("tan")) {
// 生成常见角度
int[] commonAngles = {0, 30, 45, 60, 90, 120, 135, 150, 180, 210, 225, 270, 300, 315, 330};
int angle = commonAngles[random.nextInt(commonAngles.length)];
expression.append(" ").append(operators.get(i)).append("(").append(angle).append("°)");
// 计算三角函数值
double trigValue = calculateTrigFunction(operators.get(i), angle);
operands.set(i + 1, trigValue);
} else {
expression.append(" ").append(operators.get(i)).append(" ").append(operands.get(i + 1).intValue());
}
}
expression.append(" = ?");
// 计算表达式结果
int result = calculateSeniorCompoundExpression(operands, operators);
return new String[]{expression.toString(), String.valueOf(result)};
}
/**
*
*/
private String[] generateSeniorCompoundExpression(int operatorCount) {
StringBuilder expression = new StringBuilder();
List<Double> operands = new ArrayList<>();
List<String> operators = new ArrayList<>();
// 生成操作数(运算符数量+1个操作数
for (int i = 0; i <= operatorCount; i++) {
operands.add((double)(MIN_OPERAND_VALUE + random.nextInt(MAX_OPERAND_VALUE)));
}
// 生成运算符(包含三角函数)
String[] availableOps = {"+", "-", "*", "/", "sin", "cos", "tan"};
for (int i = 0; i < operatorCount; i++) {
operators.add(availableOps[random.nextInt(availableOps.length)]);
}
// 构建表达式字符串
expression.append(operands.get(0).intValue());
for (int i = 0; i < operatorCount; i++) {
if (operators.get(i).equals("sin") || operators.get(i).equals("cos") || operators.get(i).equals("tan")) {
// 生成常见角度
int[] commonAngles = {0, 30, 45, 60, 90, 120, 135, 150, 180, 210, 225, 270, 300, 315, 330};
int angle = commonAngles[random.nextInt(commonAngles.length)];
expression.append(" ").append(operators.get(i)).append("(").append(angle).append("°)");
// 计算三角函数值
double trigValue = calculateTrigFunction(operators.get(i), angle);
operands.set(i + 1, trigValue);
} else {
expression.append(" ").append(operators.get(i)).append(" ").append(operands.get(i + 1).intValue());
}
}
expression.append(" = ?");
// 计算表达式结果
int result = calculateSeniorCompoundExpression(operands, operators);
return new String[]{expression.toString(), String.valueOf(result)};
}
/**
*
*/
private String[] generateAdvancedCompoundExpression(int operatorCount) {
StringBuilder expression = new StringBuilder();
List<Integer> operands = new ArrayList<>();
List<String> operators = new ArrayList<>();
// 生成操作数(运算符数量+1个操作数
for (int i = 0; i <= operatorCount; i++) {
operands.add(MIN_OPERAND_VALUE + random.nextInt(MAX_OPERAND_VALUE));
}
// 生成运算符(包含平方运算)
String[] availableOps = {"+", "-", "*", "/", "²"};
for (int i = 0; i < operatorCount; i++) {
operators.add(availableOps[random.nextInt(availableOps.length)]);
}
// 构建表达式字符串
expression.append(operands.get(0));
for (int i = 0; i < operatorCount; i++) {
if (operators.get(i).equals("²")) {
expression.append("²");
} else {
expression.append(" ").append(operators.get(i)).append(" ").append(operands.get(i + 1));
}
}
expression.append(" = ?");
// 计算表达式结果
int result = calculateAdvancedCompoundExpression(operands, operators);
return new String[]{expression.toString(), String.valueOf(result)};
}
/**
*
*/
private int calculateCompoundExpressionWithDivision(List<Integer> operands, List<String> operators) {
// 先处理乘除法,再处理加减法
List<Integer> numbers = new ArrayList<>(operands);
List<String> ops = new ArrayList<>(operators);
// 第一轮:处理乘除法
for (int i = 0; i < ops.size(); i++) {
if (ops.get(i).equals("*")) {
int result = numbers.get(i) * numbers.get(i + 1);
numbers.set(i, result);
numbers.remove(i + 1);
ops.remove(i);
i--; // 调整索引
} else if (ops.get(i).equals("/")) {
if (numbers.get(i + 1) != 0) {
int result = numbers.get(i) / numbers.get(i + 1);
numbers.set(i, result);
numbers.remove(i + 1);
ops.remove(i);
i--; // 调整索引
} else {
// 避免除零错误,重新生成
numbers.set(i + 1, 1 + random.nextInt(MAX_OPERAND_VALUE));
int result = numbers.get(i) / numbers.get(i + 1);
numbers.set(i, result);
numbers.remove(i + 1);
ops.remove(i);
i--; // 调整索引
}
}
}
// 第二轮:处理加减法
int result = numbers.get(0);
for (int i = 0; i < ops.size(); i++) {
if (ops.get(i).equals("+")) {
result += numbers.get(i + 1);
} else if (ops.get(i).equals("-")) {
result -= numbers.get(i + 1);
}
}
return result;
}
/**
* /
*/
private int calculateJuniorCompoundExpression(List<Integer> operands, List<String> operators) {
List<Integer> numbers = new ArrayList<>(operands);
List<String> ops = new ArrayList<>(operators);
// 第一轮:处理平方和开方运算
processSquareAndRootOperations(numbers, ops);
// 第二轮:处理乘除法
processMultiplicationAndDivision(numbers, ops);
// 第三轮:处理加减法
return processAdditionAndSubtraction(numbers, ops);
}
/**
*
*/
private void processSquareAndRootOperations(List<Integer> numbers, List<String> ops) {
for (int i = 0; i < ops.size(); i++) {
if (ops.get(i).equals("²")) {
int result = numbers.get(i) * numbers.get(i);
numbers.set(i, result);
ops.remove(i);
i--; // 调整索引
} else if (ops.get(i).equals("√")) {
// 开方运算已经在生成时处理了
ops.remove(i);
i--; // 调整索引
}
}
}
/**
*
*/
private void processMultiplicationAndDivision(List<Integer> numbers, List<String> ops) {
for (int i = 0; i < ops.size(); i++) {
if (ops.get(i).equals("*")) {
int result = numbers.get(i) * numbers.get(i + 1);
numbers.set(i, result);
numbers.remove(i + 1);
ops.remove(i);
i--; // 调整索引
} else if (ops.get(i).equals("/")) {
handleDivision(numbers, ops, i);
i--; // 调整索引
}
}
}
/**
*
*/
private void handleDivision(List<Integer> numbers, List<String> ops, int i) {
if (numbers.get(i + 1) != 0) {
int result = numbers.get(i) / numbers.get(i + 1);
numbers.set(i, result);
numbers.remove(i + 1);
ops.remove(i);
} else {
// 避免除零错误,重新生成
numbers.set(i + 1, 1 + random.nextInt(MAX_OPERAND_VALUE));
int result = numbers.get(i) / numbers.get(i + 1);
numbers.set(i, result);
numbers.remove(i + 1);
ops.remove(i);
}
}
/**
*
*/
private int processAdditionAndSubtraction(List<Integer> numbers, List<String> ops) {
int result = numbers.get(0);
for (int i = 0; i < ops.size(); i++) {
if (ops.get(i).equals("+")) {
result += numbers.get(i + 1);
} else if (ops.get(i).equals("-")) {
result -= numbers.get(i + 1);
}
}
return result;
}
/**
*
*/
private int calculateSeniorCompoundExpression(List<Double> operands, List<String> operators) {
List<Double> numbers = new ArrayList<>(operands);
List<String> ops = new ArrayList<>(operators);
// 第一轮:处理三角函数运算
processTrigonometricOperations(numbers, ops);
// 第二轮:处理乘除法
processDoubleMultiplicationAndDivision(numbers, ops);
// 第三轮:处理加减法
double result = processDoubleAdditionAndSubtraction(numbers, ops);
return (int) Math.round(result);
}
/**
*
*/
private void processTrigonometricOperations(List<Double> numbers, List<String> ops) {
for (int i = 0; i < ops.size(); i++) {
if (ops.get(i).equals("sin") || ops.get(i).equals("cos") || ops.get(i).equals("tan")) {
// 三角函数运算已经在生成时处理了
ops.remove(i);
i--; // 调整索引
}
}
}
/**
*
*/
private void processDoubleMultiplicationAndDivision(List<Double> numbers, List<String> ops) {
for (int i = 0; i < ops.size(); i++) {
if (ops.get(i).equals("*")) {
double result = numbers.get(i) * numbers.get(i + 1);
numbers.set(i, result);
numbers.remove(i + 1);
ops.remove(i);
i--; // 调整索引
} else if (ops.get(i).equals("/")) {
handleDoubleDivision(numbers, ops, i);
i--; // 调整索引
}
}
}
/**
*
*/
private void handleDoubleDivision(List<Double> numbers, List<String> ops, int i) {
if (numbers.get(i + 1) != 0) {
double result = numbers.get(i) / numbers.get(i + 1);
numbers.set(i, result);
numbers.remove(i + 1);
ops.remove(i);
} else {
// 避免除零错误,重新生成
numbers.set(i + 1, 1.0 + random.nextInt(MAX_OPERAND_VALUE));
double result = numbers.get(i) / numbers.get(i + 1);
numbers.set(i, result);
numbers.remove(i + 1);
ops.remove(i);
}
}
/**
*
*/
private double processDoubleAdditionAndSubtraction(List<Double> numbers, List<String> ops) {
double result = numbers.get(0);
for (int i = 0; i < ops.size(); i++) {
if (ops.get(i).equals("+")) {
result += numbers.get(i + 1);
} else if (ops.get(i).equals("-")) {
result -= numbers.get(i + 1);
}
}
return result;
}
/**
*
*/
private int calculateAdvancedCompoundExpression(List<Integer> operands, List<String> operators) {
List<Integer> numbers = new ArrayList<>(operands);
List<String> ops = new ArrayList<>(operators);
// 第一轮:处理平方运算
processSquareOperations(numbers, ops);
// 第二轮:处理乘除法
processMultiplicationAndDivision(numbers, ops);
// 第三轮:处理加减法
return processAdditionAndSubtraction(numbers, ops);
}
/**
*
*/
private void processSquareOperations(List<Integer> numbers, List<String> ops) {
for (int i = 0; i < ops.size(); i++) {
if (ops.get(i).equals("²")) {
int result = numbers.get(i) * numbers.get(i);
numbers.set(i, result);
ops.remove(i);
i--; // 调整索引
}
}
}
/**
*
*/

@ -123,27 +123,11 @@ public class EmailService {
*/
private String createEmailContent(String verificationCode) {
StringBuilder html = new StringBuilder();
appendHtmlHeader(html);
appendHtmlStyles(html);
appendHtmlBody(html, verificationCode);
return html.toString();
}
/**
* HTML
*/
private void appendHtmlHeader(StringBuilder html) {
html.append("<!DOCTYPE html>");
html.append("<html>");
html.append("<head>");
html.append("<meta charset=\"UTF-8\">");
html.append("<title>邮箱验证码</title>");
}
/**
* HTML
*/
private void appendHtmlStyles(StringBuilder html) {
html.append("<style>");
html.append("body { font-family: Arial, sans-serif; background-color: #f5f5f5; margin: 0; padding: 20px; }");
html.append(".container { max-width: 600px; margin: 0 auto; background-color: white; border-radius: 10px; box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1); overflow: hidden; }");
@ -156,61 +140,19 @@ public class EmailService {
html.append(".warning { background-color: #fff3cd; border: 1px solid #ffeaa7; border-radius: 5px; padding: 15px; margin: 20px 0; color: #856404; }");
html.append("</style>");
html.append("</head>");
}
/**
* HTML
*/
private void appendHtmlBody(StringBuilder html, String verificationCode) {
html.append("<body>");
html.append("<div class=\"container\">");
appendEmailHeader(html);
appendEmailContent(html, verificationCode);
appendEmailFooter(html);
html.append("</div>");
html.append("</body>");
html.append("</html>");
}
/**
*
*/
private void appendEmailHeader(StringBuilder html) {
html.append("<div class=\"header\">");
html.append("<h1>数学考试系统</h1>");
html.append("<p>邮箱验证码</p>");
html.append("</div>");
}
/**
*
*/
private void appendEmailContent(StringBuilder html, String verificationCode) {
html.append("<div class=\"content\">");
html.append("<h2>您好!</h2>");
html.append("<p>您正在注册数学考试系统,请使用以下验证码完成注册:</p>");
appendVerificationCode(html, verificationCode);
appendWarningSection(html);
html.append("<p>如果您没有注册数学考试系统,请忽略此邮件。</p>");
html.append("<p>祝您使用愉快!</p>");
html.append("<p><strong>数学考试系统团队</strong></p>");
html.append("</div>");
}
/**
*
*/
private void appendVerificationCode(StringBuilder html, String verificationCode) {
html.append("<div class=\"verification-code\">");
html.append("<p><strong>验证码:</strong></p>");
html.append("<div class=\"code\">").append(verificationCode).append("</div>");
html.append("</div>");
}
/**
*
*/
private void appendWarningSection(StringBuilder html) {
html.append("<div class=\"warning\">");
html.append("<p><strong>重要提示:</strong></p>");
html.append("<ul>");
@ -219,16 +161,19 @@ public class EmailService {
html.append("<li>如非本人操作,请忽略此邮件</li>");
html.append("</ul>");
html.append("</div>");
}
/**
*
*/
private void appendEmailFooter(StringBuilder html) {
html.append("<p>如果您没有注册数学考试系统,请忽略此邮件。</p>");
html.append("<p>祝您使用愉快!</p>");
html.append("<p><strong>数学考试系统团队</strong></p>");
html.append("</div>");
html.append("<div class=\"footer\">");
html.append("<p>此邮件由系统自动发送,请勿回复</p>");
html.append("<p>2024 数学考试系统. All rights reserved.</p>");
html.append("</div>");
html.append("</div>");
html.append("</body>");
html.append("</html>");
return html.toString();
}

@ -140,12 +140,6 @@ public class ExamController {
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) {
@ -238,27 +232,13 @@ public boolean checkUserPassword(String username, String password) {
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;");
}
// 更新用户密码
public void updateUserPassword(String username, String newPassword) {
Account account = userMap.get(username);
if (account != null) {
account.password = newPassword;
}
}
private void startExam() {
try {

@ -1,215 +0,0 @@
package com.example.mathsystemtogether;
import javafx.fxml.FXML;
import javafx.scene.control.*;
import javafx.scene.layout.VBox;
import javafx.scene.layout.HBox;
import javafx.scene.text.Font;
import javafx.scene.text.FontWeight;
import javafx.scene.paint.Color;
import javafx.stage.Stage;
import java.util.List;
/**
*
*/
public class ExamDetailsController {
@FXML private Label examInfoLabel;
@FXML private ScrollPane detailsScrollPane;
@FXML private VBox detailsContainer;
@FXML private Button scrollToTopButton;
@FXML private Button scrollToBottomButton;
@FXML private Button closeButton;
// 数据成员
private List<Question> examQuestions;
private List<String> userAnswers;
private String username;
private String level;
/**
*
*/
public void setExamDetails(List<Question> questions, List<String> answers, String username, String level) {
this.examQuestions = questions;
this.userAnswers = answers;
this.username = username;
this.level = level;
// 更新界面显示
updateDisplay();
}
/**
*
*/
private void updateDisplay() {
// 更新考试信息
examInfoLabel.setText(String.format("用户: %s | 级别: %s | 题目: %d题", username, level, examQuestions.size()));
// 清空容器
detailsContainer.getChildren().clear();
// 添加每道题的详细信息
for (int i = 0; i < examQuestions.size(); i++) {
Question question = examQuestions.get(i);
String userAnswer = i < userAnswers.size() ? userAnswers.get(i) : "未作答";
boolean isCorrect = question.isCorrect(userAnswer);
// 创建题目详情卡片
VBox questionCard = createQuestionCard(i + 1, question, userAnswer, isCorrect);
detailsContainer.getChildren().add(questionCard);
}
}
/**
*
*/
private VBox createQuestionCard(int questionNumber, Question question, String userAnswer, boolean isCorrect) {
VBox card = createCardContainer(isCorrect);
// 题目编号和状态
HBox headerBox = createHeaderBox(questionNumber, isCorrect);
// 题目内容
Label questionLabel = createQuestionLabel(question);
// 选项
VBox optionsBox = createOptionsBox(question, userAnswer);
// 答案信息
HBox answerBox = createAnswerBox(userAnswer, question);
// 添加到卡片
card.getChildren().addAll(headerBox, questionLabel, optionsBox, answerBox);
return card;
}
/**
*
*/
private VBox createCardContainer(boolean isCorrect) {
VBox card = new VBox();
card.setSpacing(10);
card.setStyle("-fx-background-color: " + (isCorrect ? "rgba(144,238,144,0.3)" : "rgba(255,182,193,0.3)") +
"; -fx-background-radius: 10; -fx-padding: 15; -fx-border-color: " +
(isCorrect ? "#90EE90" : "#FFB6C1") + "; -fx-border-radius: 10; -fx-border-width: 2;");
return card;
}
/**
*
*/
private HBox createHeaderBox(int questionNumber, boolean isCorrect) {
HBox headerBox = new HBox();
headerBox.setSpacing(10);
Label questionNumLabel = new Label("第 " + questionNumber + " 题");
questionNumLabel.setFont(Font.font("System", FontWeight.BOLD, 16));
questionNumLabel.setTextFill(Color.DARKBLUE);
Label statusLabel = new Label(isCorrect ? "✓ 正确" : "✗ 错误");
statusLabel.setFont(Font.font("System", FontWeight.BOLD, 14));
statusLabel.setTextFill(isCorrect ? Color.GREEN : Color.RED);
headerBox.getChildren().addAll(questionNumLabel, statusLabel);
return headerBox;
}
/**
*
*/
private Label createQuestionLabel(Question question) {
Label questionLabel = new Label("题目: " + question.getQuestionText());
questionLabel.setFont(Font.font("System", 14));
questionLabel.setWrapText(true);
return questionLabel;
}
/**
*
*/
private VBox createOptionsBox(Question question, String userAnswer) {
VBox optionsBox = new VBox();
optionsBox.setSpacing(5);
Label optionALabel = new Label("A. " + question.getOptionA());
Label optionBLabel = new Label("B. " + question.getOptionB());
Label optionCLabel = new Label("C. " + question.getOptionC());
Label optionDLabel = new Label("D. " + question.getOptionD());
// 高亮用户答案和正确答案
highlightAnswer(optionALabel, question.getOptionA(), userAnswer, question.getCorrectAnswer());
highlightAnswer(optionBLabel, question.getOptionB(), userAnswer, question.getCorrectAnswer());
highlightAnswer(optionCLabel, question.getOptionC(), userAnswer, question.getCorrectAnswer());
highlightAnswer(optionDLabel, question.getOptionD(), userAnswer, question.getCorrectAnswer());
optionsBox.getChildren().addAll(optionALabel, optionBLabel, optionCLabel, optionDLabel);
return optionsBox;
}
/**
*
*/
private HBox createAnswerBox(String userAnswer, Question question) {
HBox answerBox = new HBox();
answerBox.setSpacing(20);
Label userAnswerLabel = new Label("你的答案: " + userAnswer);
userAnswerLabel.setFont(Font.font("System", FontWeight.BOLD, 12));
userAnswerLabel.setTextFill(Color.BLUE);
Label correctAnswerLabel = new Label("正确答案: " + question.getCorrectAnswer());
correctAnswerLabel.setFont(Font.font("System", FontWeight.BOLD, 12));
correctAnswerLabel.setTextFill(Color.GREEN);
answerBox.getChildren().addAll(userAnswerLabel, correctAnswerLabel);
return answerBox;
}
/**
*
*/
private void highlightAnswer(Label optionLabel, String optionValue, String userAnswer, String correctAnswer) {
optionLabel.setFont(Font.font("System", 12));
if (optionValue.equals(correctAnswer)) {
// 正确答案 - 绿色背景
optionLabel.setStyle("-fx-background-color: rgba(144,238,144,0.5); -fx-background-radius: 5; -fx-padding: 5; -fx-font-weight: bold;");
} else if (optionValue.equals(userAnswer) && !userAnswer.equals(correctAnswer)) {
// 用户错误答案 - 红色背景
optionLabel.setStyle("-fx-background-color: rgba(255,182,193,0.5); -fx-background-radius: 5; -fx-padding: 5; -fx-font-weight: bold;");
} else {
// 其他选项 - 默认样式
optionLabel.setStyle("-fx-padding: 5;");
}
}
/**
*
*/
@FXML
private void handleScrollToTop() {
detailsScrollPane.setVvalue(0.0);
}
/**
*
*/
@FXML
private void handleScrollToBottom() {
detailsScrollPane.setVvalue(1.0);
}
/**
*
*/
@FXML
private void handleClose() {
Stage stage = (Stage) closeButton.getScene().getWindow();
stage.close();
}
}

@ -1,206 +0,0 @@
package com.example.mathsystemtogether;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.scene.Scene;
import javafx.scene.control.*;
import javafx.stage.Stage;
import java.util.List;
/**
*
*/
public class ExamResultController {
@FXML private Label titleLabel;
@FXML private Label subtitleLabel;
@FXML private Label scoreLabel;
@FXML private Label correctCountLabel;
@FXML private Label totalCountLabel;
@FXML private Label accuracyLabel;
@FXML private Label gradeLabel;
@FXML private Label commentLabel;
@FXML private Button continueButton;
@FXML private Button exitButton;
@FXML private Button detailsButton;
// 数据成员
private List<Question> examQuestions;
private List<String> userAnswers;
private String username;
private String level;
private int score;
private int correctCount;
private int totalCount;
private double accuracy;
/**
*
*/
public void setExamResult(List<Question> questions, List<String> answers, String username, String level) {
this.examQuestions = questions;
this.userAnswers = answers;
this.username = username;
this.level = level;
this.totalCount = questions.size();
// 计算成绩
calculateScore();
// 更新界面显示
updateDisplay();
}
/**
*
*/
private void calculateScore() {
correctCount = 0;
for (int i = 0; i < examQuestions.size(); i++) {
Question question = examQuestions.get(i);
String userAnswer = i < userAnswers.size() ? userAnswers.get(i) : "";
if (question.isCorrect(userAnswer)) {
correctCount++;
}
}
score = (int) Math.round((double) correctCount / totalCount * 100);
accuracy = (double) correctCount / totalCount * 100;
}
/**
*
*/
private void updateDisplay() {
// 更新分数显示
scoreLabel.setText(String.format("得分: %d分", score));
correctCountLabel.setText(String.format("正确: %d题", correctCount));
totalCountLabel.setText(String.format("总计: %d题", totalCount));
accuracyLabel.setText(String.format("正确率: %.1f%%", accuracy));
// 更新成绩评价
String grade = getGrade(score);
String comment = getComment(score);
gradeLabel.setText(grade);
commentLabel.setText(comment);
// 根据成绩调整颜色
updateGradeColor(score);
}
/**
*
*/
private String getGrade(int score) {
if (score >= 90) return "优秀";
else if (score >= 80) return "良好";
else if (score >= 70) return "中等";
else if (score >= 60) return "及格";
else return "不及格";
}
/**
*
*/
private String getComment(int score) {
if (score >= 90) return "表现非常出色!继续保持!";
else if (score >= 80) return "表现良好,还有提升空间!";
else if (score >= 70) return "表现中等,需要加强练习!";
else if (score >= 60) return "刚刚及格,需要更多努力!";
else return "需要认真学习,多加练习!";
}
/**
*
*/
private void updateGradeColor(int score) {
String color;
if (score >= 90) color = "#2E8B57"; // 绿色
else if (score >= 80) color = "#32CD32"; // 浅绿色
else if (score >= 70) color = "#FFD700"; // 金色
else if (score >= 60) color = "#FF8C00"; // 橙色
else color = "#DC143C"; // 红色
gradeLabel.setStyle("-fx-font-size: 24; -fx-font-weight: bold; -fx-text-fill: " + color + ";");
}
/**
*
*/
@FXML
private void handleContinueExam() {
try {
// 关闭当前窗口
Stage currentStage = (Stage) continueButton.getScene().getWindow();
currentStage.close();
// 打开考试设置界面,让用户选择题目数量和难度
FXMLLoader loader = new FXMLLoader(getClass().getResource("exam-view.fxml"));
Scene scene = new Scene(loader.load(), 1000, 900);
Stage stage = new Stage();
stage.setTitle("数学考试系统");
stage.setScene(scene);
// 获取主界面控制器并设置用户信息
ExamController examController = loader.getController();
examController.setUserForContinueExam(username, level);
stage.show();
} catch (Exception e) {
showAlert("错误", "打开考试设置界面时出错:" + e.getMessage());
}
}
/**
* 退
*/
@FXML
private void handleExitSystem() {
// 关闭当前窗口
Stage currentStage = (Stage) exitButton.getScene().getWindow();
currentStage.close();
}
/**
*
*/
@FXML
private void handleShowDetails() {
try {
// 打开详细信息窗口
FXMLLoader loader = new FXMLLoader(getClass().getResource("exam-details-view.fxml"));
Scene scene = new Scene(loader.load(), 300, 700);
Stage detailsStage = new Stage();
detailsStage.setTitle("详细答题情况");
detailsStage.setScene(scene);
detailsStage.setResizable(true);
detailsStage.setMinWidth(800);
detailsStage.setMinHeight(600);
// 传递数据给详细信息控制器
ExamDetailsController controller = loader.getController();
controller.setExamDetails(examQuestions, userAnswers, username, level);
detailsStage.show();
} catch (Exception e) {
showAlert("错误", "打开详细信息时出错:" + e.getMessage());
}
}
/**
*
*/
private void showAlert(String title, String message) {
Alert alert = new Alert(Alert.AlertType.INFORMATION);
alert.setTitle(title);
alert.setHeaderText(null);
alert.setContentText(message);
alert.showAndWait();
}
}

@ -4,7 +4,10 @@ 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 javafx.animation.Timeline;
import javafx.animation.KeyFrame;
import javafx.util.Duration;
@ -28,7 +31,6 @@ public class ExamTakingController {
@FXML private ToggleGroup answerGroup;
@FXML private Button submitButton;
@FXML private Button nextButton;
@FXML private Button prevButton;
@FXML private Button exitExamButton;
@FXML private ProgressBar progressBar;
@FXML private Label progressLabel;
@ -115,57 +117,10 @@ public class ExamTakingController {
optionC.setText("C. " + question.getOptionC());
optionD.setText("D. " + question.getOptionD());
// 恢复之前保存的答案选择
restorePreviousAnswer();
// 清除之前的选择
answerGroup.selectToggle(null);
// 更新按钮状态
updateButtonStates();
updateProgress();
}
/**
*
*/
private void restorePreviousAnswer() {
String savedAnswer = userAnswers.get(currentQuestionIndex);
if (savedAnswer != null) {
// 根据保存的答案值找到对应的选项
Question question = examQuestions.get(currentQuestionIndex);
if (savedAnswer.equals(question.getOptionA())) {
answerGroup.selectToggle(optionA);
} else if (savedAnswer.equals(question.getOptionB())) {
answerGroup.selectToggle(optionB);
} else if (savedAnswer.equals(question.getOptionC())) {
answerGroup.selectToggle(optionC);
} else if (savedAnswer.equals(question.getOptionD())) {
answerGroup.selectToggle(optionD);
}
} else {
// 没有保存的答案,清除选择
answerGroup.selectToggle(null);
}
}
/**
*
*/
private void saveCurrentAnswer() {
RadioButton selectedOption = (RadioButton) answerGroup.getSelectedToggle();
if (selectedOption != null) {
String answer = getAnswerValue(selectedOption.getText().substring(0, 1));
userAnswers.put(currentQuestionIndex, answer);
}
}
/**
*
*/
private void updateButtonStates() {
// 上一题按钮状态
prevButton.setVisible(currentQuestionIndex > 0);
// 下一题按钮状态
if (currentQuestionIndex == examQuestions.size() - 1) {
submitButton.setText("✅ 提交并完成考试");
nextButton.setVisible(false);
@ -173,6 +128,8 @@ public class ExamTakingController {
submitButton.setText("✅ 提交答案");
nextButton.setVisible(true);
}
updateProgress();
}
private void updateProgress() {
@ -216,22 +173,10 @@ public class ExamTakingController {
}
@FXML
private void handleNextQuestion() {
// 保存当前答案(如果有选择的话)
saveCurrentAnswer();
currentQuestionIndex++;
displayCurrentQuestion();
}
@FXML
private void handlePreviousQuestion() {
if (currentQuestionIndex > 0) {
// 保存当前答案(如果有选择的话)
saveCurrentAnswer();
currentQuestionIndex--;
displayCurrentQuestion();
}
}
@FXML
private void handleExitExam() {
if (showExitConfirmation()) {
@ -261,56 +206,44 @@ public class ExamTakingController {
// 停止计时器
timer.stop();
// 准备用户答案列表
List<String> userAnswersList = prepareUserAnswersList();
// 计算成绩
int correctCount = 0;
StringBuilder resultDetails = new StringBuilder();
// 关闭当前考试窗口
closeCurrentExamWindow();
for (int i = 0; i < examQuestions.size(); i++) {
Question question = examQuestions.get(i);
String userAnswer = userAnswers.get(i);
boolean isCorrect = question.isCorrect(userAnswer);
// 打开结果界面
openResultWindow(userAnswersList);
if (isCorrect) {
correctCount++;
}
} catch (Exception e) {
showAlert("错误", "显示结果时出错:" + e.getMessage());
}
}
resultDetails.append("第").append(i + 1).append("题: ");
resultDetails.append(question.getQuestionText()).append("\n");
resultDetails.append("你的答案: ").append(userAnswer != null ? userAnswer : "未作答").append(" ");
resultDetails.append("正确答案: ").append(question.getCorrectAnswer()).append(" ");
resultDetails.append(isCorrect ? "✓" : "✗").append("\n\n");
}
/**
*
*/
private List<String> prepareUserAnswersList() {
List<String> userAnswersList = new ArrayList<>();
for (int i = 0; i < examQuestions.size(); i++) {
String answer = userAnswers.get(i);
userAnswersList.add(answer != null ? answer : "");
}
return userAnswersList;
}
int score = (int) Math.round((double) correctCount / examQuestions.size() * 100);
/**
*
*/
private void closeCurrentExamWindow() {
Stage currentStage = (Stage) submitButton.getScene().getWindow();
currentStage.close();
}
// 显示结果对话框
Alert resultAlert = new Alert(Alert.AlertType.INFORMATION);
resultAlert.setTitle("考试完成");
resultAlert.setHeaderText("🎉 考试结果");
resultAlert.setContentText(String.format(
"得分: %d分\n正确: %d题\n总计: %d题\n正确率: %.1f%%",
score, correctCount, examQuestions.size(), (double) correctCount / examQuestions.size() * 100
));
resultAlert.showAndWait();
// 返回主菜单
returnToMainMenu();
/**
*
*/
private void openResultWindow(List<String> userAnswersList) throws Exception {
FXMLLoader loader = new FXMLLoader(getClass().getResource("exam-result-view.fxml"));
Scene scene = new Scene(loader.load(), 600, 700);
Stage resultStage = new Stage();
resultStage.setTitle("考试结果");
resultStage.setScene(scene);
resultStage.setResizable(false);
// 传递数据给结果控制器
ExamResultController controller = loader.getController();
controller.setExamResult(examQuestions, userAnswersList, username, level);
resultStage.show();
} catch (Exception e) {
showAlert("错误", "显示结果时出错:" + e.getMessage());
}
}
private void returnToMainMenu() {

@ -7,16 +7,17 @@ import javafx.stage.Stage;
import java.io.IOException;
public class HelloApplication extends Application {
public class HelloApplication extends Application {
@Override
public void start(Stage stage) throws IOException {
FXMLLoader fxmlLoader = new FXMLLoader(HelloApplication.class.getResource("exam-view.fxml"));
Scene scene = new Scene(fxmlLoader.load(), 900, 800);
Scene scene = new Scene(fxmlLoader.load(), 900, 900);
stage.setTitle("数学考试系统");
stage.setResizable(true);
stage.setScene(scene);
stage.show();
}
public static void main(String[] args) {
launch();
}

@ -37,18 +37,11 @@ public class RegisterController {
private static final String EMAIL_REGEX = "^[A-Za-z0-9+_.-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,}$";
private static final Pattern EMAIL_PATTERN = Pattern.compile(EMAIL_REGEX);
// 密码强度验证正则表达式
private static final String PASSWORD_REGEX = "^(?=.*[a-z])(?=.*[A-Z])(?=.*\\d).+$";
private static final Pattern PASSWORD_PATTERN = Pattern.compile(PASSWORD_REGEX);
// 用户数据文件路径
private static final String USER_DATA_FILE = "user_data.txt";
// 邮件服务
private EmailService emailService;
// 原始登录界面的引用
private Stage originalLoginStage;
@FXML
public void initialize() {
@ -63,14 +56,6 @@ public class RegisterController {
showStatus("⚠️ 邮件服务未配置请检查mail.properties文件", true);
}
}
/**
*
* @param originalStage
*/
public void setOriginalLoginStage(Stage originalStage) {
this.originalLoginStage = originalStage;
}
private void setupLevelComboBox() {
ObservableList<String> levels = FXCollections.observableArrayList("小学", "初中", "高中");
@ -82,40 +67,22 @@ public class RegisterController {
private void handleSendCode() {
String email = emailField.getText().trim();
if (!validateEmailInput(email)) {
return;
}
if (!emailService.isAvailable()) {
showStatus("❌ 邮件服务不可用,请检查配置", true);
return;
}
generateAndSendCode(email);
startSendCodeCountdown();
}
/**
*
*/
private boolean validateEmailInput(String email) {
if (email.isEmpty()) {
showStatus("请输入邮箱地址", true);
return false;
return;
}
if (!isValidEmail(email)) {
showStatus("请输入有效的邮箱地址", true);
return false;
return;
}
// 检查邮件服务是否可用
if (!emailService.isAvailable()) {
showStatus("❌ 邮件服务不可用,请检查配置", true);
return;
}
return true;
}
/**
*
*/
private void generateAndSendCode(String email) {
// 生成6位数字验证码
generatedCode = emailService.generateVerificationCode();
codeGenerationTime = System.currentTimeMillis();
@ -128,30 +95,18 @@ public class RegisterController {
boolean success = emailService.sendVerificationCode(email, generatedCode);
javafx.application.Platform.runLater(() -> {
handleSendCodeResult(success, email);
if (success) {
showStatus("✅ 验证码已发送到邮箱:" + email + ",请查收邮件", false);
// 启用注册按钮
registerButton.setDisable(false);
} else {
showStatus("❌ 邮件发送失败,请检查邮箱地址或稍后重试", true);
// 显示验证码用于调试(仅开发环境)
showStatus("❌ 邮件发送失败,请检查邮箱地址或稍后重试。验证码:" + generatedCode + "(调试用)", true);
}
});
}).start();
}
/**
*
*/
private void handleSendCodeResult(boolean success, String email) {
if (success) {
showStatus("✅ 验证码已发送到邮箱:" + email + ",请查收邮件", false);
// 启用注册按钮
registerButton.setDisable(false);
} else {
showStatus("❌ 邮件发送失败,请检查邮箱地址或稍后重试", true);
// 显示验证码用于调试(仅开发环境)
showStatus("❌ 邮件发送失败,请检查邮箱地址或稍后重试。验证码:" + generatedCode + "(调试用)", true);
}
}
/**
*
*/
private void startSendCodeCountdown() {
// 禁用发送按钮60秒
sendCodeButton.setDisable(true);
sendCodeButton.setText("60秒后可重发");
@ -170,114 +125,77 @@ public class RegisterController {
String level = levelComboBox.getValue();
// 验证输入
if (!validateInput(username, password, confirmPassword, email, verificationCode)) {
return;
}
// 验证验证码
if (!verifyCode(verificationCode)) {
showStatus("验证码错误或已过期", true);
return;
}
// 检查用户名和邮箱是否已存在
if (!checkUserAvailability(username, email)) {
return;
}
// 保存用户信息
if (saveUserData(username, password, email, level)) {
showStatus("注册成功!正在跳转到登录界面...", false);
scheduleRedirectToLogin();
} else {
showStatus("注册失败,请重试", true);
}
}
/**
*
*/
private boolean validateInput(String username, String password, String confirmPassword,
String email, String verificationCode) {
if (username.isEmpty() || password.isEmpty() || confirmPassword.isEmpty() ||
email.isEmpty() || verificationCode.isEmpty()) {
showStatus("请填写所有字段", true);
return false;
return;
}
if (username.length() < 3) {
showStatus("用户名至少需要3个字符", true);
return false;
return;
}
if (password.length() < 6) {
showStatus("密码至少需要6个字符", true);
return false;
}
if (!isValidPassword(password)) {
showStatus("密码必须包含大小写字母和数字", true);
return false;
return;
}
if (!password.equals(confirmPassword)) {
showStatus("两次输入的密码不一致", true);
return false;
return;
}
if (!isValidEmail(email)) {
showStatus("请输入有效的邮箱地址", true);
return false;
return;
}
return true;
}
// 验证验证码
if (!verifyCode(verificationCode)) {
showStatus("验证码错误或已过期", true);
return;
}
/**
*
*/
private boolean checkUserAvailability(String username, String email) {
// 检查用户名是否已存在
if (isUserExists(username)) {
showStatus("用户名已存在,请选择其他用户名", true);
return false;
return;
}
// 检查邮箱是否已注册
if (isEmailExists(email)) {
showStatus("该邮箱已被注册", true);
return false;
return;
}
return true;
}
/**
*
*/
private void scheduleRedirectToLogin() {
Timer timer = new Timer();
timer.schedule(new TimerTask() {
@Override
public void run() {
javafx.application.Platform.runLater(() -> {
handleBackToLogin();
});
}
}, 2000);
// 保存用户信息
if (saveUserData(username, password, email, level)) {
showStatus("注册成功!正在跳转到登录界面...", false);
// 延迟跳转到登录界面
Timer timer = new Timer();
timer.schedule(new TimerTask() {
@Override
public void run() {
javafx.application.Platform.runLater(() -> {
handleBackToLogin();
});
}
}, 2000);
} else {
showStatus("注册失败,请重试", true);
}
}
@FXML
private void handleBackToLogin() {
try {
// 关闭当前注册窗口
// 关闭当前窗口
Stage currentStage = (Stage) backToLoginButton.getScene().getWindow();
currentStage.close();
// 关闭原始登录界面(如果存在)
if (originalLoginStage != null && originalLoginStage.isShowing()) {
originalLoginStage.close();
}
// 打开新的登录界面
// 打开登录界面
FXMLLoader loader = new FXMLLoader(getClass().getResource("exam-view.fxml"));
Scene scene = new Scene(loader.load(), 900, 900);
Stage loginStage = new Stage();
@ -311,14 +229,6 @@ public class RegisterController {
private boolean isValidEmail(String email) {
return EMAIL_PATTERN.matcher(email).matches();
}
/**
*
*
*/
private boolean isValidPassword(String password) {
return PASSWORD_PATTERN.matcher(password).matches();
}
private boolean isUserExists(String username) {
try {

@ -1,3 +0,0 @@
Manifest-Version: 1.0
Main-Class: com.example.mathsystemtogether.HelloApplication

@ -1,48 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.geometry.Insets?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<?import javafx.scene.text.*?>
<AnchorPane xmlns="http://javafx.com/javafx/11.0.1" xmlns:fx="http://javafx.com/fxml/1" fx:controller="com.example.mathsystemtogether.ExamDetailsController">
<children>
<!-- 背景渐变 -->
<AnchorPane style="-fx-background-color: linear-gradient(135deg, #667eea 0%, #764ba2 100%);">
<children>
<!-- 主要内容区域 -->
<VBox alignment="CENTER" spacing="20.0" style="-fx-background-color: rgba(255,255,255,0.95); -fx-background-radius: 20; -fx-padding: 30; -fx-effect: dropshadow(gaussian, rgba(0,0,0,0.3), 20, 0, 0, 5);" AnchorPane.bottomAnchor="30.0" AnchorPane.leftAnchor="30.0" AnchorPane.rightAnchor="30.0" AnchorPane.topAnchor="30.0">
<children>
<!-- 标题区域 -->
<VBox alignment="CENTER" spacing="10.0">
<Label text="📊 详细答题情况" style="-fx-font-size: 28; -fx-font-weight: bold; -fx-text-fill: #2E8B57; -fx-effect: dropshadow(gaussian, rgba(0,0,0,0.3), 5, 0, 0, 2);"/>
<Label fx:id="examInfoLabel" text="用户: 张三 | 级别: 小学 | 题目: 10题" style="-fx-font-size: 16; -fx-text-fill: #666666;"/>
</VBox>
<!-- 答题详情区域 -->
<ScrollPane fx:id="detailsScrollPane" fitToWidth="true" hbarPolicy="NEVER" vbarPolicy="AS_NEEDED"
style="-fx-background-color: rgba(248,249,250,0.8); -fx-background-radius: 10; -fx-border-color: #E0E0E0; -fx-border-radius: 10; -fx-border-width: 1;"
prefHeight="400" maxHeight="500">
<content>
<VBox fx:id="detailsContainer" spacing="15.0" style="-fx-padding: 20;">
<!-- 详细信息将在这里动态添加 -->
</VBox>
</content>
</ScrollPane>
<!-- 滚动控制按钮区域 -->
<HBox alignment="CENTER" spacing="15.0">
<Button fx:id="scrollToTopButton" text="⬆️ 回到顶部" onAction="#handleScrollToTop" style="-fx-background-color: linear-gradient(to right, #4CAF50, #45a049); -fx-text-fill: white; -fx-background-radius: 8; -fx-padding: 8 15; -fx-font-size: 12; -fx-font-weight: bold; -fx-effect: dropshadow(gaussian, rgba(0,0,0,0.2), 3, 0, 0, 1);"/>
<Button fx:id="scrollToBottomButton" text="⬇️ 到底部" onAction="#handleScrollToBottom" style="-fx-background-color: linear-gradient(to right, #2196F3, #1976D2); -fx-text-fill: white; -fx-background-radius: 8; -fx-padding: 8 15; -fx-font-size: 12; -fx-font-weight: bold; -fx-effect: dropshadow(gaussian, rgba(0,0,0,0.2), 3, 0, 0, 1);"/>
</HBox>
<!-- 操作按钮区域 -->
<HBox alignment="CENTER" spacing="20.0">
<Button fx:id="closeButton" text="❌ 关闭" onAction="#handleClose" style="-fx-background-color: linear-gradient(to right, #DC143C, #B22222); -fx-text-fill: white; -fx-background-radius: 12; -fx-padding: 12 25; -fx-font-size: 14; -fx-font-weight: bold; -fx-effect: dropshadow(gaussian, rgba(0,0,0,0.3), 5, 0, 0, 2);"/>
</HBox>
</children>
</VBox>
</children>
</AnchorPane>
</children>
</AnchorPane>

@ -1,63 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.geometry.Insets?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<?import javafx.scene.text.*?>
<AnchorPane xmlns="http://javafx.com/javafx/11.0.1" xmlns:fx="http://javafx.com/fxml/1" fx:controller="com.example.mathsystemtogether.ExamResultController">
<children>
<!-- 背景渐变 -->
<AnchorPane style="-fx-background-color: linear-gradient(135deg, #667eea 0%, #764ba2 100%);">
<children>
<!-- 主要内容区域 -->
<VBox alignment="CENTER" spacing="30.0" style="-fx-background-color: rgba(255,255,255,0.95); -fx-background-radius: 20; -fx-padding: 40; -fx-effect: dropshadow(gaussian, rgba(0,0,0,0.3), 20, 0, 0, 5);" AnchorPane.bottomAnchor="50.0" AnchorPane.leftAnchor="50.0" AnchorPane.rightAnchor="50.0" AnchorPane.topAnchor="50.0">
<children>
<!-- 标题区域 -->
<VBox alignment="CENTER" spacing="10.0">
<Label fx:id="titleLabel" text="🎉 考试完成!" style="-fx-font-size: 36; -fx-font-weight: bold; -fx-text-fill: #2E8B57; -fx-effect: dropshadow(gaussian, rgba(0,0,0,0.3), 5, 0, 0, 2);"/>
<Label fx:id="subtitleLabel" text="恭喜您完成了数学考试" style="-fx-font-size: 18; -fx-text-fill: #666666;"/>
</VBox>
<!-- 分数显示区域 -->
<VBox alignment="CENTER" spacing="20.0" style="-fx-background-color: linear-gradient(135deg, #f093fb 0%, #f5576c 100%); -fx-background-radius: 15; -fx-padding: 30; -fx-effect: dropshadow(gaussian, rgba(0,0,0,0.2), 10, 0, 0, 3);">
<children>
<Label fx:id="scoreLabel" text="得分: 85分" style="-fx-font-size: 48; -fx-font-weight: bold; -fx-text-fill: white; -fx-effect: dropshadow(gaussian, rgba(0,0,0,0.5), 8, 0, 0, 2);"/>
<HBox alignment="CENTER" spacing="40.0">
<VBox alignment="CENTER" spacing="5.0">
<Label fx:id="correctCountLabel" text="正确: 8题" style="-fx-font-size: 16; -fx-text-fill: white; -fx-font-weight: bold;"/>
<Label text="正确题目" style="-fx-font-size: 12; -fx-text-fill: rgba(255,255,255,0.8);"/>
</VBox>
<VBox alignment="CENTER" spacing="5.0">
<Label fx:id="totalCountLabel" text="总计: 10题" style="-fx-font-size: 16; -fx-text-fill: white; -fx-font-weight: bold;"/>
<Label text="总题目" style="-fx-font-size: 12; -fx-text-fill: rgba(255,255,255,0.8);"/>
</VBox>
<VBox alignment="CENTER" spacing="5.0">
<Label fx:id="accuracyLabel" text="正确率: 80%" style="-fx-font-size: 16; -fx-text-fill: white; -fx-font-weight: bold;"/>
<Label text="准确率" style="-fx-font-size: 12; -fx-text-fill: rgba(255,255,255,0.8);"/>
</VBox>
</HBox>
</children>
</VBox>
<!-- 成绩评价区域 -->
<VBox alignment="CENTER" spacing="10.0">
<Label fx:id="gradeLabel" text="优秀" style="-fx-font-size: 24; -fx-font-weight: bold; -fx-text-fill: #2E8B57;"/>
<Label fx:id="commentLabel" text="表现非常出色!继续保持!" style="-fx-font-size: 16; -fx-text-fill: #666666;"/>
</VBox>
<!-- 操作按钮区域 -->
<HBox alignment="CENTER" spacing="30.0">
<Button fx:id="continueButton" text="🔄 继续做题" onAction="#handleContinueExam" style="-fx-background-color: linear-gradient(to right, #32CD32, #228B22); -fx-text-fill: white; -fx-background-radius: 12; -fx-padding: 15 30; -fx-font-size: 16; -fx-font-weight: bold; -fx-effect: dropshadow(gaussian, rgba(0,0,0,0.3), 5, 0, 0, 2);"/>
<Button fx:id="exitButton" text="🚪 退出系统" onAction="#handleExitSystem" style="-fx-background-color: linear-gradient(to right, #DC143C, #B22222); -fx-text-fill: white; -fx-background-radius: 12; -fx-padding: 15 30; -fx-font-size: 16; -fx-font-weight: bold; -fx-effect: dropshadow(gaussian, rgba(0,0,0,0.3), 5, 0, 0, 2);"/>
</HBox>
<!-- 详细信息按钮 -->
<Button fx:id="detailsButton" text="📊 查看详细答题情况" onAction="#handleShowDetails" style="-fx-background-color: linear-gradient(to right, #8A2BE2, #9932CC); -fx-text-fill: white; -fx-background-radius: 12; -fx-padding: 12 25; -fx-font-size: 14; -fx-font-weight: bold; -fx-effect: dropshadow(gaussian, rgba(0,0,0,0.3), 5, 0, 0, 2);"/>
</children>
</VBox>
</children>
</AnchorPane>
</children>
</AnchorPane>

@ -72,7 +72,6 @@
<!-- 操作按钮区域 -->
<HBox spacing="20.0" alignment="CENTER" style="-fx-background-color: rgba(255,255,255,0.9); -fx-background-radius: 15; -fx-padding: 20; -fx-effect: dropshadow(gaussian, rgba(139,0,139,0.2), 8, 0, 0, 3);">
<Button fx:id="prevButton" text="⬅️ 上一题" onAction="#handlePreviousQuestion" style="-fx-background-color: linear-gradient(to right, #FF8C00, #FF6347); -fx-text-fill: white; -fx-background-radius: 12; -fx-padding: 15 30; -fx-font-size: 16; -fx-font-weight: bold; -fx-effect: dropshadow(gaussian, rgba(0,0,0,0.3), 5, 0, 0, 2);"/>
<Button fx:id="submitButton" text="✅ 提交答案" onAction="#handleSubmitAnswer" style="-fx-background-color: linear-gradient(to right, #32CD32, #228B22); -fx-text-fill: white; -fx-background-radius: 12; -fx-padding: 15 30; -fx-font-size: 16; -fx-font-weight: bold; -fx-effect: dropshadow(gaussian, rgba(0,0,0,0.3), 5, 0, 0, 2);"/>
<Button fx:id="nextButton" text="➡️ 下一题" onAction="#handleNextQuestion" style="-fx-background-color: linear-gradient(to right, #8A2BE2, #9932CC); -fx-text-fill: white; -fx-background-radius: 12; -fx-padding: 15 30; -fx-font-size: 16; -fx-font-weight: bold; -fx-effect: dropshadow(gaussian, rgba(0,0,0,0.3), 5, 0, 0, 2);"/>
<Button fx:id="exitExamButton" text="🚪 退出考试" onAction="#handleExitExam" style="-fx-background-color: linear-gradient(to right, #DC143C, #B22222); -fx-text-fill: white; -fx-background-radius: 12; -fx-padding: 15 30; -fx-font-size: 16; -fx-font-weight: bold; -fx-effect: dropshadow(gaussian, rgba(0,0,0,0.3), 5, 0, 0, 2);"/>

@ -1,3 +1,2 @@
666|123456789|252436951@qq.com|小学|1760166999971
wgll|Ymh123456|ymhlovesLQX@163.com|小学|1760261535669
wgll|123456|ymhlovesLQX@163.com|小学|1760162416490
666|123456789|252436951@qq.com|小学|1760166999971

Loading…
Cancel
Save