Compare commits

..

3 Commits

@ -0,0 +1,10 @@
<component name="ArtifactManager">
<artifact type="jar" build-on-make="true" name="MathLearningSoftware:jar">
<output-path>$PROJECT_DIR$/out/artifacts/MathLearningSoftware_jar</output-path>
<root id="archive" name="MathLearningSoftware.jar">
<element id="module-output" name="MathLearningSoftware" />
<element id="extracted-dir" path="$MAVEN_REPOSITORY$/com/sun/mail/javax.mail/1.6.2/javax.mail-1.6.2.jar" path-in-jar="/" />
<element id="extracted-dir" path="$MAVEN_REPOSITORY$/javax/activation/activation/1.1/activation-1.1.jar" path-in-jar="/" />
</root>
</artifact>
</component>

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<project version="4"> <project version="4">
<component name="ProjectRootManager" version="2" project-jdk-name="23" project-jdk-type="JavaSDK"> <component name="ProjectRootManager" version="2" languageLevel="JDK_22" project-jdk-name="23" project-jdk-type="JavaSDK">
<output url="file://$PROJECT_DIR$/out" /> <output url="file://$PROJECT_DIR$/out" />
</component> </component>
</project> </project>

@ -1,4 +1,9 @@
2023@qq.com|971458|Hsh2006|true 2023@qq.com|hahah|971458|Hsh2005|true
202326010221@168.com|829554||false 14498@qq.com|ly|862004||false
14498@qq.com|862004||false 1449892469@qq.com|ly|137032|Ly2004|true
1449892469@qq.com|137032|Ly2004|true 1577@163.com|txj|972753|Txj123456|true
2095885186@qq.com|null|060613||false
3045193232@qq.com|null|056850||false
38425875@qq.com|ewfguwfe|360732|nI1234|true
2768350566@qq.com|x|715819|Ni1234|true
2281638407@qq.com|guogu|214092|Guo*12|true

@ -1,40 +1,46 @@
# 数学学习软件 # 数学学习软件
## 项目简介 ## 项目简介
这是一个基于Java Swing开发的数学学习软件旨在为不同学段的学生提供个性化的数学练习体验。软件支持用户注册、登录、密码管理以及根据小学、初中、高中不同难度生成相应的数学题目。 这是一个基于Java Swing开发的数学学习软件旨在为不同学段的学生提供个性化的数学练习体验。软件支持用户注册、登录、密码管理以及根据小学、初中、高中不同难度生成相应的数学题目。
## 功能特性 ## 功能特性
### 用户管理 ### 用户管理
- **用户注册**: 通过邮箱注册,系统发送注册码验证 - **用户注册**: 通过邮箱注册,系统发送注册码验证
- **用户登录**: 安全的邮箱密码登录机制 - **用户登录**: 安全的邮箱密码登录机制
- **密码管理**: 支持密码修改,密码强度验证 - **密码管理**: 支持密码修改,密码强度验证
### 学习功能 ### 学习功能
- **难度选择**: 小学、初中、高中三个难度级别 - **难度选择**: 小学、初中、高中三个难度级别
- **题目生成**: 根据难度自动生成相应数学题目 - **题目生成**: 根据难度自动生成相应数学题目
- **答题系统**: 选择题形式,实时反馈 - **答题系统**: 选择题形式,实时反馈
- **成绩统计**: 答题结果分析和详细报告 - **成绩统计**: 答题结果分析和详细报告
### 技术特点 ### 技术特点
- 基于Java Swing的图形界面 - 基于Java Swing的图形界面
- JSON数据持久化存储 - 数据持久化存储
- 模块化设计,易于扩展 - 模块化设计,易于扩展
- 代码结构清晰,注释完整 - 代码结构清晰,注释完整
## 系统要求 ## 系统要求
- Java 8 或更高版本 - JDK24 或更高版本
- 支持Java Swing的桌面环境 - 支持Java Swing的桌面环境
- 至少 100MB 可用磁盘空间 - 至少 100MB 可用磁盘空间
## 安装和运行 ## 注意
- 发送验证码邮件的邮箱账号为```3602474328@qq.com```
### 方法一使用预编译JAR文件 - 包含验证码的邮件可能会被归类为垃圾邮件,若迟迟未收到验证码请到垃圾箱中翻找一下
- 用户名和密码都不能出现字符```|```,否则判定为非法
1. 下载项目的最新发布版本 - 登录时使用的是邮箱+密码登录,不是用户名+密码
2. 确保系统已安装Java运行环境
3. 双击JAR文件运行或使用命令行 ## 安装和运行
```bash
### 方法一使用预编译JAR文件
1. 下载项目的最新发布版本
2. 确保系统已安装Java运行环境
3. 双击JAR文件运行或使用命令行
```bash
java -jar MathLearningSoftware.jar java -jar MathLearningSoftware.jar

@ -0,0 +1,3 @@
Manifest-Version: 1.0
Main-Class: com.mathlearning.Main

@ -52,7 +52,16 @@ public class AuthController {
} }
} }
public boolean completeRegistration(String email, String registrationCode, String password) { public boolean isUsernameAvailable(String username) {
User user = userService.getUserByUsername(username);
if (user != null && user.isRegistered()) {
return false;
} else {
return true;
}
}
public boolean completeRegistration(String email, String user_name, String password) {
try { try {
/* /*
if (!authService.validateRegistrationCode(email, registrationCode)) { if (!authService.validateRegistrationCode(email, registrationCode)) {
@ -61,7 +70,7 @@ public class AuthController {
*/ */
User user = userService.getUserByEmail(email); User user = userService.getUserByEmail(email);
if (user != null && authService.validatePassword(password)) { if (user != null && authService.validatePassword(password)) {
return userService.completeRegistration(email, password); return userService.completeRegistration(email, user_name, password);
} }
return false; return false;
} catch (Exception e) { } catch (Exception e) {
@ -128,6 +137,10 @@ public class AuthController {
return currentUser != null ? currentUser.getEmail() : null; return currentUser != null ? currentUser.getEmail() : null;
} }
public String getCurrentUserName() {
return currentUser != null ? currentUser.getUser_name() : null;
}
public boolean isCodeRegistered(String email, String registrationCode) { public boolean isCodeRegistered(String email, String registrationCode) {
if (!authService.validateRegistrationCode(email, registrationCode)) { if (!authService.validateRegistrationCode(email, registrationCode)) {
return false; return false;

@ -31,9 +31,9 @@ public class QuestionController {
System.out.println((i + 1) + ". " + q.getQuestionText()); System.out.println((i + 1) + ". " + q.getQuestionText());
String[] options = q.getOptions(); String[] options = q.getOptions();
for (int j = 0; j < options.length; j++) { for (int j = 0; j < options.length; j++) {
System.out.println(" " + (char)('A' + j) + ". " + options[j]); System.out.println(" " + (char) ('A' + j) + ". " + options[j]);
} }
System.out.println(" 正确答案: " + (char)('A' + q.getCorrectIndex())); System.out.println(" 正确答案: " + (char) ('A' + q.getCorrectIndex()));
System.out.println(); System.out.println();
} }
} }
@ -137,4 +137,4 @@ public class QuestionController {
this.currentQuestionIndex = index; this.currentQuestionIndex = index;
} }
} }
} }

@ -7,35 +7,35 @@ import java.util.Set;
public abstract class AbstractQuestionGenerator implements QuestionGenerator { public abstract class AbstractQuestionGenerator implements QuestionGenerator {
@Override @Override
public List<Question> generateQuestions(String level, int count) { public List<Question> generateQuestions(String level, int count) {
List<Question> questions = new ArrayList<>(); List<Question> questions = new ArrayList<>();
Set<String> questionTexts = new HashSet<>(); Set<String> questionTexts = new HashSet<>();
for (int i = 0; i < count; i++) { for (int i = 0; i < count; i++) {
Question question = generateUniqueQuestion(level, i, questionTexts); Question question = generateUniqueQuestion(level, i, questionTexts);
if (question != null) { if (question != null) {
questions.add(question); questions.add(question);
} }
}
return questions;
} }
private Question generateUniqueQuestion(String level, int index, Set<String> questionTexts) { return questions;
Question question; }
int attempt = 0;
do {
question = generateQuestion(level, index);
attempt++;
} while (question != null && questionTexts.contains(question.getQuestionText()) && attempt < 10);
if (question != null) { private Question generateUniqueQuestion(String level, int index, Set<String> questionTexts) {
questionTexts.add(question.getQuestionText()); Question question;
} int attempt = 0;
do {
question = generateQuestion(level, index);
attempt++;
} while (question != null && questionTexts.contains(question.getQuestionText()) && attempt < 10);
return question; if (question != null) {
questionTexts.add(question.getQuestionText());
} }
protected abstract Question generateQuestion(String level, int index); return question;
}
protected abstract Question generateQuestion(String level, int index);
} }

@ -7,186 +7,186 @@ import java.util.Random;
import java.util.Set; import java.util.Set;
public abstract class BaseQuestionGenerator { public abstract class BaseQuestionGenerator {
protected Random random = new Random(); protected Random random = new Random();
public abstract Question generateQuestion(int index); public abstract Question generateQuestion(int index);
protected void generateOperands(int[] operands, int min, int max) { protected void generateOperands(int[] operands, int min, int max) {
for (int i = 0; i < operands.length; i++) { for (int i = 0; i < operands.length; i++) {
operands[i] = random.nextInt(max - min + 1) + min; operands[i] = random.nextInt(max - min + 1) + min;
}
} }
}
protected void generateOperations(int[] operations, int operationTypes) { protected void generateOperations(int[] operations, int operationTypes) {
for (int i = 0; i < operations.length; i++) { for (int i = 0; i < operations.length; i++) {
operations[i] = random.nextInt(operationTypes); operations[i] = random.nextInt(operationTypes);
}
} }
}
protected void appendOperator(StringBuilder sb, int operation) { protected void appendOperator(StringBuilder sb, int operation) {
switch (operation) { switch (operation) {
case 0: sb.append(" + "); break; case 0: sb.append(" + "); break;
case 1: sb.append(" - "); break; case 1: sb.append(" - "); break;
case 2: sb.append(" × "); break; case 2: sb.append(" × "); break;
case 3: sb.append(" ÷ "); break; case 3: sb.append(" ÷ "); break;
}
} }
}
protected boolean isValidAnswer(double answer) { protected boolean isValidAnswer(double answer) {
return !(answer < 0 || Double.isNaN(answer) || Double.isInfinite(answer)); return !(answer < 0 || Double.isNaN(answer) || Double.isInfinite(answer));
} }
// 修改使用double进行精确计算只在最后保留小数 // 修改使用double进行精确计算只在最后保留小数
protected double calculateExpression(double[] values, int[] operations) { protected double calculateExpression(double[] values, int[] operations) {
List<Double> numbers = new ArrayList<>(); List<Double> numbers = new ArrayList<>();
List<Integer> ops = new ArrayList<>(); List<Integer> ops = new ArrayList<>();
for (double value : values) numbers.add(value); for (double value : values) numbers.add(value);
for (int operation : operations) ops.add(operation); for (int operation : operations) ops.add(operation);
processMultiplicationAndDivision(numbers, ops); processMultiplicationAndDivision(numbers, ops);
return processAdditionAndSubtraction(numbers, ops); return processAdditionAndSubtraction(numbers, ops);
} }
protected double calculateWithoutParentheses(int[] operands, int[] operations) { protected double calculateWithoutParentheses(int[] operands, int[] operations) {
double[] doubleOperands = new double[operands.length]; double[] doubleOperands = new double[operands.length];
for (int i = 0; i < operands.length; i++) { for (int i = 0; i < operands.length; i++) {
doubleOperands[i] = operands[i]; doubleOperands[i] = operands[i];
}
return calculateExpression(doubleOperands, operations);
} }
return calculateExpression(doubleOperands, operations);
}
protected double calculateWithoutParentheses(List<Integer> numbers, List<Integer> ops) { protected double calculateWithoutParentheses(List<Integer> numbers, List<Integer> ops) {
double[] doubleNumbers = new double[numbers.size()]; double[] doubleNumbers = new double[numbers.size()];
for (int i = 0; i < numbers.size(); i++) { for (int i = 0; i < numbers.size(); i++) {
doubleNumbers[i] = numbers.get(i); doubleNumbers[i] = numbers.get(i);
}
int[] intOps = new int[ops.size()];
for (int i = 0; i < ops.size(); i++) {
intOps[i] = ops.get(i);
}
return calculateExpression(doubleNumbers, intOps);
} }
private void processMultiplicationAndDivision(List<Double> numbers, List<Integer> ops) { int[] intOps = new int[ops.size()];
for (int i = 0; i < ops.size(); i++) { for (int i = 0; i < ops.size(); i++) {
int op = ops.get(i); intOps[i] = ops.get(i);
if (op == 2 || op == 3) {
double left = numbers.get(i);
double right = numbers.get(i + 1);
double result = performOperation(left, right, op);
numbers.set(i, result);
numbers.remove(i + 1);
ops.remove(i);
i--;
}
}
} }
private double processAdditionAndSubtraction(List<Double> numbers, List<Integer> ops) { return calculateExpression(doubleNumbers, intOps);
double result = numbers.get(0); }
for (int i = 0; i < ops.size(); i++) { private void processMultiplicationAndDivision(List<Double> numbers, List<Integer> ops) {
int op = ops.get(i); for (int i = 0; i < ops.size(); i++) {
double nextNum = numbers.get(i + 1); int op = ops.get(i);
result = performOperation(result, nextNum, op); if (op == 2 || op == 3) {
} double left = numbers.get(i);
double right = numbers.get(i + 1);
double result = performOperation(left, right, op);
// 修改只在最后一步进行四舍五入保留2位小数 numbers.set(i, result);
return Math.round(result * 100) / 100.0; numbers.remove(i + 1);
ops.remove(i);
i--;
}
} }
}
private double performOperation(double left, double right, int operation) { private double processAdditionAndSubtraction(List<Double> numbers, List<Integer> ops) {
switch (operation) { double result = numbers.get(0);
case 0: return left + right;
case 1: return left - right;
case 2: return left * right;
case 3:
if (right == 0) return Double.NaN;
// 修改:直接进行除法,不在这里保留小数
return left / right;
default: return left;
}
}
protected Question generateOptions(String questionText, double answer, String level) {
String[] options = new String[4];
Set<String> usedValues = new HashSet<>();
// 修改:判断是否为整数的逻辑
boolean isIntegerAnswer = Math.abs(answer - Math.round(answer)) < 1e-10;
String correctAnswer = formatAnswer(answer, isIntegerAnswer);
options[0] = correctAnswer;
usedValues.add(correctAnswer);
generateWrongOptions(options, usedValues, answer, isIntegerAnswer);
shuffleArray(options);
int correctIndex = findCorrectIndex(options, correctAnswer); for (int i = 0; i < ops.size(); i++) {
return new Question(questionText, options, correctIndex, level); int op = ops.get(i);
double nextNum = numbers.get(i + 1);
result = performOperation(result, nextNum, op);
} }
private void generateWrongOptions(String[] options, Set<String> usedValues, // 修改只在最后一步进行四舍五入保留2位小数
double answer, boolean isIntegerAnswer) { return Math.round(result * 100) / 100.0;
for (int i = 1; i < 4; i++) { }
String wrongAnswer;
int attempts = 0;
do {
double wrongValue = generateWrongValue(answer, isIntegerAnswer);
wrongAnswer = formatAnswer(wrongValue,
Math.abs(wrongValue - Math.round(wrongValue)) < 1e-10);
attempts++;
} while (usedValues.contains(wrongAnswer) && attempts < 20);
options[i] = wrongAnswer;
usedValues.add(wrongAnswer);
}
}
private double generateWrongValue(double answer, boolean isIntegerAnswer) {
double offset = (random.nextDouble() * 5) + 1;
if (isIntegerAnswer) {
int intAnswer = (int) Math.round(answer);
int intOffset = random.nextInt(10) + 1;
double wrongValue = random.nextBoolean() ?
intAnswer + intOffset : Math.max(1, intAnswer - intOffset);
return wrongValue;
} else {
double wrongValue = random.nextBoolean() ? answer + offset : answer - offset;
// 修改错误选项也保留2位小数
return Math.round(wrongValue * 100) / 100.0;
}
}
// 修改:格式化答案,只在最后一步处理小数位数
private String formatAnswer(double answer, boolean isInteger) {
if (isInteger) {
return String.valueOf((int) Math.round(answer));
} else {
// 确保显示2位小数即使末尾是0
return String.format("%.2f", answer);
}
}
private void shuffleArray(String[] array) {
for (int i = array.length - 1; i > 0; i--) {
int j = random.nextInt(i + 1);
String temp = array[i];
array[i] = array[j];
array[j] = temp;
}
}
private int findCorrectIndex(String[] options, String correctAnswer) { private double performOperation(double left, double right, int operation) {
for (int i = 0; i < options.length; i++) { switch (operation) {
if (options[i].equals(correctAnswer)) return i; case 0: return left + right;
} case 1: return left - right;
return 0; case 2: return left * right;
} case 3:
if (right == 0) return Double.NaN;
// 修改:直接进行除法,不在这里保留小数
return left / right;
default: return left;
}
}
protected Question generateOptions(String questionText, double answer, String level) {
String[] options = new String[4];
Set<String> usedValues = new HashSet<>();
// 修改:判断是否为整数的逻辑
boolean isIntegerAnswer = Math.abs(answer - Math.round(answer)) < 1e-10;
String correctAnswer = formatAnswer(answer, isIntegerAnswer);
options[0] = correctAnswer;
usedValues.add(correctAnswer);
generateWrongOptions(options, usedValues, answer, isIntegerAnswer);
shuffleArray(options);
int correctIndex = findCorrectIndex(options, correctAnswer);
return new Question(questionText, options, correctIndex, level);
}
private void generateWrongOptions(String[] options, Set<String> usedValues,
double answer, boolean isIntegerAnswer) {
for (int i = 1; i < 4; i++) {
String wrongAnswer;
int attempts = 0;
do {
double wrongValue = generateWrongValue(answer, isIntegerAnswer);
wrongAnswer = formatAnswer(wrongValue,
Math.abs(wrongValue - Math.round(wrongValue)) < 1e-10);
attempts++;
} while (usedValues.contains(wrongAnswer) && attempts < 20);
options[i] = wrongAnswer;
usedValues.add(wrongAnswer);
}
}
private double generateWrongValue(double answer, boolean isIntegerAnswer) {
double offset = (random.nextDouble() * 5) + 1;
if (isIntegerAnswer) {
int intAnswer = (int) Math.round(answer);
int intOffset = random.nextInt(10) + 1;
double wrongValue = random.nextBoolean() ?
intAnswer + intOffset : Math.max(1, intAnswer - intOffset);
return wrongValue;
} else {
double wrongValue = random.nextBoolean() ? answer + offset : answer - offset;
// 修改错误选项也保留2位小数
return Math.round(wrongValue * 100) / 100.0;
}
}
// 修改:格式化答案,只在最后一步处理小数位数
private String formatAnswer(double answer, boolean isInteger) {
if (isInteger) {
return String.valueOf((int) Math.round(answer));
} else {
// 确保显示2位小数即使末尾是0
return String.format("%.2f", answer);
}
}
private void shuffleArray(String[] array) {
for (int i = array.length - 1; i > 0; i--) {
int j = random.nextInt(i + 1);
String temp = array[i];
array[i] = array[j];
array[j] = temp;
}
}
private int findCorrectIndex(String[] options, String correctAnswer) {
for (int i = 0; i < options.length; i++) {
if (options[i].equals(correctAnswer)) return i;
}
return 0;
}
} }

@ -1,21 +1,21 @@
package com.mathlearning.model; package com.mathlearning.model;
public class ConcreteQuestionGenerator extends AbstractQuestionGenerator { public class ConcreteQuestionGenerator extends AbstractQuestionGenerator {
private PrimaryQuestionGenerator primaryGenerator = new PrimaryQuestionGenerator(); private PrimaryQuestionGenerator primaryGenerator = new PrimaryQuestionGenerator();
private MiddleSchoolQuestionGenerator middleSchoolGenerator = new MiddleSchoolQuestionGenerator(); private MiddleSchoolQuestionGenerator middleSchoolGenerator = new MiddleSchoolQuestionGenerator();
private HighSchoolQuestionGenerator highSchoolGenerator = new HighSchoolQuestionGenerator(); private HighSchoolQuestionGenerator highSchoolGenerator = new HighSchoolQuestionGenerator();
@Override @Override
protected Question generateQuestion(String level, int index) { protected Question generateQuestion(String level, int index) {
switch (level) { switch (level) {
case "小学": case "小学":
return primaryGenerator.generateQuestion(index); return primaryGenerator.generateQuestion(index);
case "初中": case "初中":
return middleSchoolGenerator.generateQuestion(index); return middleSchoolGenerator.generateQuestion(index);
case "高中": case "高中":
return highSchoolGenerator.generateQuestion(index); return highSchoolGenerator.generateQuestion(index);
default: default:
return primaryGenerator.generateQuestion(index); return primaryGenerator.generateQuestion(index);
}
} }
}
} }

@ -1,112 +1,112 @@
package com.mathlearning.model; package com.mathlearning.model;
public class HighSchoolQuestionGenerator extends BaseQuestionGenerator { public class HighSchoolQuestionGenerator extends BaseQuestionGenerator {
private static final int[] SPECIAL_ANGLES = {0, 15, 30, 45, 60, 75, 90}; private static final int[] SPECIAL_ANGLES = {0, 15, 30, 45, 60, 75, 90};
@Override @Override
public Question generateQuestion(int index) { public Question generateQuestion(int index) {
int operandCount = random.nextInt(5) + 1; int operandCount = random.nextInt(5) + 1;
int[] operands = new int[operandCount]; int[] operands = new int[operandCount];
int[] operations = new int[Math.max(0, operandCount - 1)]; int[] operations = new int[Math.max(0, operandCount - 1)];
boolean[] hasTrigOp = new boolean[operandCount]; boolean[] hasTrigOp = new boolean[operandCount];
int[] trigFunctions = new int[operandCount]; int[] trigFunctions = new int[operandCount];
ensureTrigOperation(hasTrigOp, trigFunctions, operandCount); ensureTrigOperation(hasTrigOp, trigFunctions, operandCount);
String questionText; String questionText;
double answer; double answer;
do { do {
generateOperandsWithTrig(operands, hasTrigOp); generateOperandsWithTrig(operands, hasTrigOp);
generateOperations(operations, 4); generateOperations(operations, 4);
questionText = buildQuestionText(operands, operations, hasTrigOp, trigFunctions); questionText = buildQuestionText(operands, operations, hasTrigOp, trigFunctions);
answer = calculateAnswer(operands, operations, hasTrigOp, trigFunctions); answer = calculateAnswer(operands, operations, hasTrigOp, trigFunctions);
} while (!isValidAnswer(answer) || Math.abs(answer) > 10000); } while (!isValidAnswer(answer) || Math.abs(answer) > 10000);
return generateOptions(questionText, answer, "高中"); return generateOptions(questionText, answer, "高中");
} }
private void ensureTrigOperation(boolean[] hasTrigOp, int[] trigFunctions, int operandCount) {
boolean hasTrigOperation = false;
for (int i = 0; i < operandCount; i++) { private void ensureTrigOperation(boolean[] hasTrigOp, int[] trigFunctions, int operandCount) {
hasTrigOp[i] = random.nextDouble() < 0.6; boolean hasTrigOperation = false;
if (hasTrigOp[i]) hasTrigOperation = true;
}
if (!hasTrigOperation && operandCount > 0) { for (int i = 0; i < operandCount; i++) {
int idx = random.nextInt(operandCount); hasTrigOp[i] = random.nextDouble() < 0.6;
hasTrigOp[idx] = true; if (hasTrigOp[i]) hasTrigOperation = true;
trigFunctions[idx] = random.nextInt(3);
}
} }
private void generateOperandsWithTrig(int[] operands, boolean[] hasTrigOp) { if (!hasTrigOperation && operandCount > 0) {
for (int i = 0; i < operands.length; i++) { int idx = random.nextInt(operandCount);
operands[i] = hasTrigOp[i] ? hasTrigOp[idx] = true;
SPECIAL_ANGLES[random.nextInt(SPECIAL_ANGLES.length)] : trigFunctions[idx] = random.nextInt(3);
random.nextInt(100) + 1;
}
} }
}
private String buildQuestionText(int[] operands, int[] operations, private void generateOperandsWithTrig(int[] operands, boolean[] hasTrigOp) {
boolean[] hasTrigOp, int[] trigFunctions) { for (int i = 0; i < operands.length; i++) {
StringBuilder sb = new StringBuilder(); operands[i] = hasTrigOp[i] ?
SPECIAL_ANGLES[random.nextInt(SPECIAL_ANGLES.length)] :
random.nextInt(100) + 1;
}
}
for (int i = 0; i < operands.length; i++) { private String buildQuestionText(int[] operands, int[] operations,
if (i > 0) appendOperator(sb, operations[i - 1]); boolean[] hasTrigOp, int[] trigFunctions) {
StringBuilder sb = new StringBuilder();
if (hasTrigOp[i]) { for (int i = 0; i < operands.length; i++) {
appendTrigFunction(sb, operands[i], trigFunctions[i]); if (i > 0) appendOperator(sb, operations[i - 1]);
} else {
sb.append(operands[i]);
}
}
sb.append(" = ?"); if (hasTrigOp[i]) {
return sb.toString(); appendTrigFunction(sb, operands[i], trigFunctions[i]);
} else {
sb.append(operands[i]);
}
} }
private void appendTrigFunction(StringBuilder sb, int operand, int trigFunction) { sb.append(" = ?");
switch (trigFunction) { return sb.toString();
case 0: sb.append("sin(").append(operand).append("°)"); break; }
case 1: sb.append("cos(").append(operand).append("°)"); break;
case 2: sb.append("tan(").append(operand).append("°)"); break;
}
}
private double calculateAnswer(int[] operands, int[] operations, private void appendTrigFunction(StringBuilder sb, int operand, int trigFunction) {
boolean[] hasTrigOp, int[] trigFunctions) { switch (trigFunction) {
double[] processedValues = processTrigOperations(operands, hasTrigOp, trigFunctions); case 0: sb.append("sin(").append(operand).append("°)"); break;
return calculateExpression(processedValues, operations); case 1: sb.append("cos(").append(operand).append("°)"); break;
case 2: sb.append("tan(").append(operand).append("°)"); break;
}
}
private double calculateAnswer(int[] operands, int[] operations,
boolean[] hasTrigOp, int[] trigFunctions) {
double[] processedValues = processTrigOperations(operands, hasTrigOp, trigFunctions);
return calculateExpression(processedValues, operations);
}
private double[] processTrigOperations(int[] operands, boolean[] hasTrigOp, int[] trigFunctions) {
double[] processedValues = new double[operands.length];
for (int i = 0; i < operands.length; i++) {
if (hasTrigOp[i]) {
processedValues[i] = calculateTrigFunction(operands[i], trigFunctions[i]);
} else {
processedValues[i] = operands[i];
}
} }
private double[] processTrigOperations(int[] operands, boolean[] hasTrigOp, int[] trigFunctions) { return processedValues;
double[] processedValues = new double[operands.length]; }
for (int i = 0; i < operands.length; i++) {
if (hasTrigOp[i]) {
processedValues[i] = calculateTrigFunction(operands[i], trigFunctions[i]);
} else {
processedValues[i] = operands[i];
}
}
return processedValues; private double calculateTrigFunction(int angle, int trigFunction) {
} double radians = Math.toRadians(angle);
private double calculateTrigFunction(int angle, int trigFunction) { switch (trigFunction) {
double radians = Math.toRadians(angle); case 0: return Math.sin(radians);
case 1: return Math.cos(radians);
switch (trigFunction) { case 2:
case 0: return Math.sin(radians); if (angle % 180 == 90 && angle % 360 != 270) return Double.NaN;
case 1: return Math.cos(radians); return Math.tan(radians);
case 2: default: return 0;
if (angle % 180 == 90 && angle % 360 != 270) return Double.NaN;
return Math.tan(radians);
default: return 0;
}
} }
}
} }

@ -2,90 +2,90 @@ package com.mathlearning.model;
public class MiddleSchoolQuestionGenerator extends BaseQuestionGenerator { public class MiddleSchoolQuestionGenerator extends BaseQuestionGenerator {
@Override @Override
public Question generateQuestion(int index) { public Question generateQuestion(int index) {
int operandCount = random.nextInt(5) + 1; int operandCount = random.nextInt(5) + 1;
int[] operands = new int[operandCount]; int[] operands = new int[operandCount];
int[] operations = new int[Math.max(0, operandCount - 1)]; int[] operations = new int[Math.max(0, operandCount - 1)];
boolean[] hasSpecialOp = new boolean[operandCount]; boolean[] hasSpecialOp = new boolean[operandCount];
int[] specialOpTypes = new int[operandCount]; int[] specialOpTypes = new int[operandCount];
ensureSpecialOperation(hasSpecialOp, specialOpTypes, operandCount); ensureSpecialOperation(hasSpecialOp, specialOpTypes, operandCount);
String questionText; String questionText;
double answer; double answer;
do { do {
generateOperands(operands, 1, 100); generateOperands(operands, 1, 100);
generateOperations(operations, 4); generateOperations(operations, 4);
questionText = buildQuestionText(operands, operations, hasSpecialOp, specialOpTypes); questionText = buildQuestionText(operands, operations, hasSpecialOp, specialOpTypes);
answer = calculateAnswer(operands, operations, hasSpecialOp, specialOpTypes); answer = calculateAnswer(operands, operations, hasSpecialOp, specialOpTypes);
} while (!isValidAnswer(answer) || Math.abs(answer) > 10000); } while (!isValidAnswer(answer) || Math.abs(answer) > 10000);
return generateOptions(questionText, answer, "初中"); return generateOptions(questionText, answer, "初中");
} }
private void ensureSpecialOperation(boolean[] hasSpecialOp, int[] specialOpTypes, int operandCount) {
boolean hasSpecialOperation = false;
for (int i = 0; i < operandCount; i++) { private void ensureSpecialOperation(boolean[] hasSpecialOp, int[] specialOpTypes, int operandCount) {
hasSpecialOp[i] = random.nextDouble() < 0.6; boolean hasSpecialOperation = false;
if (hasSpecialOp[i]) hasSpecialOperation = true;
}
if (!hasSpecialOperation && operandCount > 0) { for (int i = 0; i < operandCount; i++) {
int idx = random.nextInt(operandCount); hasSpecialOp[i] = random.nextDouble() < 0.6;
hasSpecialOp[idx] = true; if (hasSpecialOp[i]) hasSpecialOperation = true;
specialOpTypes[idx] = random.nextInt(2);
}
} }
private String buildQuestionText(int[] operands, int[] operations, if (!hasSpecialOperation && operandCount > 0) {
boolean[] hasSpecialOp, int[] specialOpTypes) { int idx = random.nextInt(operandCount);
StringBuilder sb = new StringBuilder(); hasSpecialOp[idx] = true;
specialOpTypes[idx] = random.nextInt(2);
}
}
for (int i = 0; i < operands.length; i++) { private String buildQuestionText(int[] operands, int[] operations,
if (i > 0) appendOperator(sb, operations[i - 1]); boolean[] hasSpecialOp, int[] specialOpTypes) {
StringBuilder sb = new StringBuilder();
if (hasSpecialOp[i]) { for (int i = 0; i < operands.length; i++) {
appendSpecialOperation(sb, operands[i], specialOpTypes[i]); if (i > 0) appendOperator(sb, operations[i - 1]);
} else {
sb.append(operands[i]);
}
}
sb.append(" = ?"); if (hasSpecialOp[i]) {
return sb.toString(); appendSpecialOperation(sb, operands[i], specialOpTypes[i]);
} else {
sb.append(operands[i]);
}
} }
private void appendSpecialOperation(StringBuilder sb, int operand, int opType) { sb.append(" = ?");
if (opType == 0) { return sb.toString();
sb.append(operand).append("²"); }
} else {
sb.append("√").append(operand);
}
}
private double calculateAnswer(int[] operands, int[] operations, private void appendSpecialOperation(StringBuilder sb, int operand, int opType) {
boolean[] hasSpecialOp, int[] specialOpTypes) { if (opType == 0) {
double[] processedValues = processSpecialOperations(operands, hasSpecialOp, specialOpTypes); sb.append(operand).append("²");
return calculateExpression(processedValues, operations); } else {
sb.append("√").append(operand);
} }
}
private double[] processSpecialOperations(int[] operands, boolean[] hasSpecialOp, int[] specialOpTypes) {
double[] processedValues = new double[operands.length]; private double calculateAnswer(int[] operands, int[] operations,
boolean[] hasSpecialOp, int[] specialOpTypes) {
for (int i = 0; i < operands.length; i++) { double[] processedValues = processSpecialOperations(operands, hasSpecialOp, specialOpTypes);
if (hasSpecialOp[i]) { return calculateExpression(processedValues, operations);
processedValues[i] = (specialOpTypes[i] == 0) ? }
operands[i] * operands[i] : Math.sqrt(operands[i]);
} else { private double[] processSpecialOperations(int[] operands, boolean[] hasSpecialOp, int[] specialOpTypes) {
processedValues[i] = operands[i]; double[] processedValues = new double[operands.length];
}
} for (int i = 0; i < operands.length; i++) {
if (hasSpecialOp[i]) {
return processedValues; processedValues[i] = (specialOpTypes[i] == 0) ?
operands[i] * operands[i] : Math.sqrt(operands[i]);
} else {
processedValues[i] = operands[i];
}
} }
return processedValues;
}
} }

@ -5,139 +5,139 @@ import java.util.List;
public class PrimaryQuestionGenerator extends BaseQuestionGenerator { public class PrimaryQuestionGenerator extends BaseQuestionGenerator {
@Override @Override
public Question generateQuestion(int index) { public Question generateQuestion(int index) {
int operandCount = random.nextInt(4) + 2; int operandCount = random.nextInt(4) + 2;
int[] operands = new int[operandCount]; int[] operands = new int[operandCount];
int[] operations = new int[operandCount - 1]; int[] operations = new int[operandCount - 1];
String questionText; String questionText;
double answer; double answer;
do { do {
generateOperands(operands, 1, 100); generateOperands(operands, 1, 100);
generateOperations(operations, 4); generateOperations(operations, 4);
boolean useParentheses = random.nextDouble() < 0.3 && operandCount >= 3; boolean useParentheses = random.nextDouble() < 0.3 && operandCount >= 3;
int[] parenthesesPositions = findParenthesesPositions(operations, useParentheses); int[] parenthesesPositions = findParenthesesPositions(operations, useParentheses);
questionText = buildQuestionText(operands, operations, questionText = buildQuestionText(operands, operations,
parenthesesPositions[0], parenthesesPositions[1]); parenthesesPositions[0], parenthesesPositions[1]);
answer = calculateAnswer(operands, operations, answer = calculateAnswer(operands, operations,
parenthesesPositions[0], parenthesesPositions[1]); parenthesesPositions[0], parenthesesPositions[1]);
} while (!isValidAnswer(answer)); } while (!isValidAnswer(answer));
return generateOptions(questionText, answer, "小学"); return generateOptions(questionText, answer, "小学");
} }
private int[] findParenthesesPositions(int[] operations, boolean useParentheses) { private int[] findParenthesesPositions(int[] operations, boolean useParentheses) {
int parenStart = -1; int parenStart = -1;
int parenEnd = -1; int parenEnd = -1;
if (useParentheses) { if (useParentheses) {
parenStart = findSuitableParenthesesPosition(operations); parenStart = findSuitableParenthesesPosition(operations);
if (parenStart != -1) { if (parenStart != -1) {
parenEnd = parenStart + 1; parenEnd = parenStart + 1;
if (parenEnd < operations.length && random.nextBoolean()) { if (parenEnd < operations.length && random.nextBoolean()) {
parenEnd++; parenEnd++;
}
}
} }
}
return new int[]{parenStart, parenEnd};
} }
private int findSuitableParenthesesPosition(int[] operations) { return new int[]{parenStart, parenEnd};
List<Integer> suitablePositions = new ArrayList<>(); }
for (int i = 0; i < operations.length; i++) { private int findSuitableParenthesesPosition(int[] operations) {
if ((operations[i] == 0 || operations[i] == 1) && i > 0) { List<Integer> suitablePositions = new ArrayList<>();
suitablePositions.add(i);
}
}
if (suitablePositions.isEmpty()) { for (int i = 0; i < operations.length; i++) {
return operations.length > 1 ? random.nextInt(operations.length - 1) : -1; if ((operations[i] == 0 || operations[i] == 1) && i > 0) {
} suitablePositions.add(i);
}
}
return suitablePositions.get(random.nextInt(suitablePositions.size())); if (suitablePositions.isEmpty()) {
return operations.length > 1 ? random.nextInt(operations.length - 1) : -1;
} }
private String buildQuestionText(int[] operands, int[] operations, int parenStart, int parenEnd) { return suitablePositions.get(random.nextInt(suitablePositions.size()));
StringBuilder sb = new StringBuilder(); }
for (int i = 0; i < operands.length; i++) { private String buildQuestionText(int[] operands, int[] operations, int parenStart, int parenEnd) {
if (i == parenStart) sb.append("("); StringBuilder sb = new StringBuilder();
sb.append(operands[i]);
if (i == parenEnd) sb.append(")");
if (i < operations.length) appendOperator(sb, operations[i]);
}
sb.append(" = ?"); for (int i = 0; i < operands.length; i++) {
return sb.toString(); if (i == parenStart) sb.append("(");
sb.append(operands[i]);
if (i == parenEnd) sb.append(")");
if (i < operations.length) appendOperator(sb, operations[i]);
} }
private double calculateAnswer(int[] operands, int[] operations, int parenStart, int parenEnd) { sb.append(" = ?");
if (parenStart == -1 || parenEnd == -1) { return sb.toString();
return calculateWithoutParentheses(operands, operations); }
}
return calculateWithParentheses(operands, operations, parenStart, parenEnd); private double calculateAnswer(int[] operands, int[] operations, int parenStart, int parenEnd) {
if (parenStart == -1 || parenEnd == -1) {
return calculateWithoutParentheses(operands, operations);
} }
private double calculateWithParentheses(int[] operands, int[] operations, int parenStart, int parenEnd) { return calculateWithParentheses(operands, operations, parenStart, parenEnd);
// 修改使用Double列表 }
List<Double> numbers = new ArrayList<>();
List<Integer> ops = new ArrayList<>();
for (int operand : operands) numbers.add((double) operand); private double calculateWithParentheses(int[] operands, int[] operations, int parenStart, int parenEnd) {
for (int operation : operations) ops.add(operation); // 修改使用Double列表
List<Double> numbers = new ArrayList<>();
List<Integer> ops = new ArrayList<>();
double parenthesesResult = calculateParenthesesContent(numbers, ops, parenStart, parenEnd); for (int operand : operands) numbers.add((double) operand);
for (int operation : operations) ops.add(operation);
if (!isValidAnswer(parenthesesResult)) return -1; double parenthesesResult = calculateParenthesesContent(numbers, ops, parenStart, parenEnd);
replaceWithParenthesesResult(numbers, ops, parenStart, parenEnd, parenthesesResult); if (!isValidAnswer(parenthesesResult)) return -1;
// 修改:调用新的方法名
return calculateDoubleList(numbers, ops);
}
private double calculateParenthesesContent(List<Double> numbers, List<Integer> ops, int start, int end) { replaceWithParenthesesResult(numbers, ops, parenStart, parenEnd, parenthesesResult);
List<Double> parenNumbers = new ArrayList<>(); // 修改:调用新的方法名
List<Integer> parenOps = new ArrayList<>(); return calculateDoubleList(numbers, ops);
}
for (int i = start; i <= end; i++) parenNumbers.add(numbers.get(i)); private double calculateParenthesesContent(List<Double> numbers, List<Integer> ops, int start, int end) {
for (int i = start; i < end; i++) parenOps.add(ops.get(i)); List<Double> parenNumbers = new ArrayList<>();
List<Integer> parenOps = new ArrayList<>();
// 修改:调用新的方法名 for (int i = start; i <= end; i++) parenNumbers.add(numbers.get(i));
return calculateDoubleList(parenNumbers, parenOps); for (int i = start; i < end; i++) parenOps.add(ops.get(i));
}
private void replaceWithParenthesesResult(List<Double> numbers, List<Integer> ops, // 修改:调用新的方法名
int start, int end, double result) { return calculateDoubleList(parenNumbers, parenOps);
int numCountToRemove = end - start + 1; }
int opCountToRemove = end - start;
for (int i = 0; i < numCountToRemove; i++) numbers.remove(start); private void replaceWithParenthesesResult(List<Double> numbers, List<Integer> ops,
for (int i = 0; i < opCountToRemove; i++) ops.remove(start); int start, int end, double result) {
int numCountToRemove = end - start + 1;
int opCountToRemove = end - start;
// 修改直接添加double结果不转换为int for (int i = 0; i < numCountToRemove; i++) numbers.remove(start);
numbers.add(start, result); for (int i = 0; i < opCountToRemove; i++) ops.remove(start);
}
// 修改:重命名方法,避免与父类冲突 // 修改直接添加double结果不转换为int
private double calculateDoubleList(List<Double> numbers, List<Integer> ops) { numbers.add(start, result);
double[] doubleNumbers = new double[numbers.size()]; }
for (int i = 0; i < numbers.size(); i++) {
doubleNumbers[i] = numbers.get(i);
}
int[] intOps = new int[ops.size()]; // 修改:重命名方法,避免与父类冲突
for (int i = 0; i < ops.size(); i++) { private double calculateDoubleList(List<Double> numbers, List<Integer> ops) {
intOps[i] = ops.get(i); double[] doubleNumbers = new double[numbers.size()];
} for (int i = 0; i < numbers.size(); i++) {
doubleNumbers[i] = numbers.get(i);
}
return calculateExpression(doubleNumbers, intOps); int[] intOps = new int[ops.size()];
for (int i = 0; i < ops.size(); i++) {
intOps[i] = ops.get(i);
} }
return calculateExpression(doubleNumbers, intOps);
}
} }

@ -1,6 +1,7 @@
package com.mathlearning.model; package com.mathlearning.model;
public class User { public class User {
private String user_name; // 从第一个版本保留
private String email; private String email;
private String password; private String password;
private String registrationCode; private String registrationCode;
@ -11,6 +12,7 @@ public class User {
this.registrationCode = registrationCode; this.registrationCode = registrationCode;
this.isRegistered = false; this.isRegistered = false;
this.password = null; this.password = null;
this.user_name = null; // 添加初始化
} }
// Getters and setters // Getters and setters
@ -22,6 +24,15 @@ public class User {
this.email = email; this.email = email;
} }
// user_name 相关方法(从第一个版本保留)
public String getUser_name() {
return user_name;
}
public void setUser_name(String user_name) {
this.user_name = user_name;
}
public String getPassword() { public String getPassword() {
return password; return password;
} }
@ -45,4 +56,4 @@ public class User {
public void setRegistered(boolean registered) { public void setRegistered(boolean registered) {
isRegistered = registered; isRegistered = registered;
} }
} }

@ -60,7 +60,10 @@ public class AuthService {
} }
public boolean validatePassword(String password) { public boolean validatePassword(String password) {
if (password == null || password.length() < 6 || password.length() > 10) { if (password == null
|| password.length() < 6
|| password.length() > 10
|| password.contains("|")) {
return false; return false;
} }

@ -27,10 +27,11 @@ public class UserService {
return true; return true;
} }
public boolean completeRegistration(String email, String password) { public boolean completeRegistration(String email, String user_name, String password) {
for (User user : users) { for (User user : users) {
if (user.getEmail().equals(email) && !user.isRegistered()) { if (user.getEmail().equals(email) && !user.isRegistered()) {
user.setPassword(password); user.setPassword(password);
user.setUser_name(user_name);
user.setRegistered(true); user.setRegistered(true);
saveUsers(); saveUsers();
return true; return true;
@ -70,6 +71,15 @@ public class UserService {
return null; return null;
} }
public User getUserByUsername(String username) {
for (User user : users) {
if (user.getUser_name() != null && user.getUser_name().equals(username)) {
return user;
}
}
return null;
}
public boolean updateUser(User updatedUser) { public boolean updateUser(User updatedUser) {
for (int i = 0; i < users.size(); i++) { for (int i = 0; i < users.size(); i++) {
if (users.get(i).getEmail().equals(updatedUser.getEmail())) { if (users.get(i).getEmail().equals(updatedUser.getEmail())) {
@ -93,10 +103,11 @@ public class UserService {
String line; String line;
while ((line = reader.readLine()) != null) { while ((line = reader.readLine()) != null) {
String[] parts = line.split("\\|"); String[] parts = line.split("\\|");
if (parts.length >= 4) { if (parts.length >= 5) {
User user = new User(parts[0], parts[1]); User user = new User(parts[0], parts[2]);
user.setPassword(parts[2]); user.setUser_name(parts[1]);
user.setRegistered(Boolean.parseBoolean(parts[3])); user.setPassword(parts[3]);
user.setRegistered(Boolean.parseBoolean(parts[4]));
userList.add(user); userList.add(user);
} }
} }
@ -116,6 +127,8 @@ public class UserService {
for (User user : users) { for (User user : users) {
String line = String line =
user.getEmail() user.getEmail()
+ "|"
+ user.getUser_name()
+ "|" + "|"
+ user.getRegistrationCode() + user.getRegistrationCode()
+ "|" + "|"

@ -75,7 +75,7 @@ public class LevelSelectionFrame extends JFrame {
// 底部显示当前用户信息 // 底部显示当前用户信息
if (authController.getCurrentUser() != null) { if (authController.getCurrentUser() != null) {
JLabel userInfoLabel = JLabel userInfoLabel =
new JLabel("当前用户: " + authController.getCurrentUser().getEmail(), JLabel.CENTER); new JLabel("当前用户: " + authController.getCurrentUser().getUser_name(), JLabel.CENTER);
userInfoLabel.setFont(new Font("Microsoft YaHei", Font.PLAIN, 12)); userInfoLabel.setFont(new Font("Microsoft YaHei", Font.PLAIN, 12));
userInfoLabel.setForeground(Color.GRAY); userInfoLabel.setForeground(Color.GRAY);
userInfoLabel.setBorder(BorderFactory.createEmptyBorder(10, 0, 0, 0)); userInfoLabel.setBorder(BorderFactory.createEmptyBorder(10, 0, 0, 0));

@ -28,7 +28,7 @@ public class PasswordChangeFrame extends JFrame {
panel.setBorder(BorderFactory.createEmptyBorder(15, 15, 15, 15)); panel.setBorder(BorderFactory.createEmptyBorder(15, 15, 15, 15));
// 显示当前用户信息 // 显示当前用户信息
JLabel userLabel = new JLabel("当前用户: " + authController.getCurrentUserEmail()); JLabel userLabel = new JLabel("当前用户: " + authController.getCurrentUserName());
userLabel.setFont(new Font("Microsoft YaHei", Font.BOLD, 12)); userLabel.setFont(new Font("Microsoft YaHei", Font.BOLD, 12));
userLabel.setForeground(new Color(0, 100, 200)); userLabel.setForeground(new Color(0, 100, 200));
@ -80,7 +80,11 @@ public class PasswordChangeFrame extends JFrame {
} else { } else {
JOptionPane.showMessageDialog( JOptionPane.showMessageDialog(
this, this,
"密码修改失败!\n" + "可能的原因:\n" + "• 原密码不正确\n" + "• 新密码不符合要求6-10位包含大小写字母和数字", "密码修改失败!\n"
+ "可能的原因:\n"
+ "• 原密码不正确\n"
+ "• 新密码不符合要求\n"
+ "• 密码要求6-10位包含大小写字母和数字且不包含非法字符|\n",
"错误", "错误",
JOptionPane.ERROR_MESSAGE); JOptionPane.ERROR_MESSAGE);
} }

@ -12,6 +12,7 @@ public class PasswordSetupFrame extends JFrame {
private AuthController authController; private AuthController authController;
private JPasswordField passwordField; private JPasswordField passwordField;
private JPasswordField confirmPasswordField; private JPasswordField confirmPasswordField;
private JTextField usernameField;
private JLabel resultLabel; private JLabel resultLabel;
public PasswordSetupFrame(String email, String code, AuthController authController) { public PasswordSetupFrame(String email, String code, AuthController authController) {
@ -24,59 +25,94 @@ public class PasswordSetupFrame extends JFrame {
private void initializeUI() { private void initializeUI() {
setTitle("设置密码"); setTitle("设置密码");
setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
setSize(450, 300); setSize(350, 400);
setLocationRelativeTo(null); setLocationRelativeTo(null);
setResizable(false); setResizable(false);
JPanel mainPanel = new JPanel(new BorderLayout(10, 10)); JPanel panel = new JPanel();
mainPanel.setBorder(BorderFactory.createEmptyBorder(20, 20, 20, 20)); panel.setLayout(null);
// 添加顶部返回按钮
JPanel topPanel = new JPanel(new BorderLayout());
JButton backButton = new JButton("← 返回注册"); JButton backButton = new JButton("← 返回注册");
backButton.setFont(new Font("Microsoft YaHei", Font.PLAIN, 12)); backButton.setFont(new Font("Microsoft YaHei", Font.PLAIN, 12));
backButton.setBackground(new Color(200, 200, 200)); backButton.setBackground(new Color(200, 200, 200));
backButton.addActionListener(e -> backToRegister()); backButton.addActionListener(e -> backToRegister());
topPanel.add(backButton, BorderLayout.WEST); backButton.setBounds(20, 20, 100, 25);
panel.add(backButton);
mainPanel.add(topPanel, BorderLayout.NORTH); JLabel titleLabel = new JLabel("用户:" + email);
JLabel titleLabel = new JLabel("用户:" + email, JLabel.CENTER);
titleLabel.setFont(new Font("Microsoft YaHei", Font.BOLD, 16)); titleLabel.setFont(new Font("Microsoft YaHei", Font.BOLD, 16));
mainPanel.add(titleLabel, BorderLayout.CENTER); titleLabel.setBounds(20, 50, 300, 20);
panel.add(titleLabel);
JPanel formPanel = new JPanel(new GridLayout(3, 2, 10, 10)); JLabel usernameLabel = new JLabel("用户名:");
usernameLabel.setFont(new Font("Microsoft YaHei", Font.PLAIN, 14));
usernameField = new JTextField();
usernameLabel.setBounds(20, 90, 100, 30);
usernameField.setBounds(100, 90, 200, 30);
JLabel passwordLabel = new JLabel("密码:"); JLabel passwordLabel = new JLabel("密码:");
passwordLabel.setFont(new Font("Microsoft YaHei", Font.PLAIN, 14)); passwordLabel.setFont(new Font("Microsoft YaHei", Font.PLAIN, 14));
passwordField = new JPasswordField(); passwordField = new JPasswordField();
passwordLabel.setBounds(20, 150, 50, 30);
passwordField.setBounds(100, 150, 200, 30);
JLabel confirmLabel = new JLabel("确认密码:"); JLabel confirmLabel = new JLabel("确认密码:");
confirmLabel.setFont(new Font("Microsoft YaHei", Font.PLAIN, 14)); confirmLabel.setFont(new Font("Microsoft YaHei", Font.PLAIN, 14));
confirmPasswordField = new JPasswordField(); confirmPasswordField = new JPasswordField();
confirmLabel.setBounds(20, 210, 80, 30);
confirmPasswordField.setBounds(100, 210, 200, 30);
JButton submitButton = new JButton("完成"); JButton submitButton = new JButton("完成");
submitButton.setFont(new Font("Microsoft YaHei", Font.PLAIN, 14)); submitButton.setFont(new Font("Microsoft YaHei", Font.PLAIN, 14));
submitButton.setBounds(110, 290, 80, 30);
formPanel.add(passwordLabel);
formPanel.add(passwordField); panel.add(usernameLabel);
formPanel.add(confirmLabel); panel.add(usernameField);
formPanel.add(confirmPasswordField); panel.add(passwordLabel);
formPanel.add(new JLabel()); panel.add(passwordField);
formPanel.add(submitButton); panel.add(confirmLabel);
panel.add(confirmPasswordField);
resultLabel = new JLabel("密码需6-10位包含大小写字母和数字", JLabel.CENTER); panel.add(new JLabel());
panel.add(submitButton);
resultLabel = new JLabel("用户名需1-8位密码需6-10位包含大小写字母和数字");
resultLabel.setFont(new Font("Microsoft YaHei", Font.PLAIN, 12)); resultLabel.setFont(new Font("Microsoft YaHei", Font.PLAIN, 12));
resultLabel.setForeground(Color.BLUE); resultLabel.setForeground(Color.BLUE);
resultLabel.setBounds(20, 240, 300, 30);
JPanel centerPanel = new JPanel(new BorderLayout()); panel.add(resultLabel);
centerPanel.add(formPanel, BorderLayout.CENTER);
centerPanel.add(resultLabel, BorderLayout.SOUTH);
mainPanel.add(centerPanel, BorderLayout.SOUTH);
submitButton.addActionListener(new SubmitAction()); submitButton.addActionListener(new SubmitAction());
add(mainPanel); add(panel);
}
private boolean examingTextField(String password, String confirmPassword, String username) {
if (password.isEmpty() || confirmPassword.isEmpty()) {
resultLabel.setText("请填写所有字段");
resultLabel.setForeground(Color.RED);
return false;
}
if (username.length() > 8) {
resultLabel.setText("用户名超过8个字符");
resultLabel.setForeground(Color.RED);
return false;
}
if (username.contains("|") || password.contains("|")) {
resultLabel.setText("用户名或密码包含非法字符|");
resultLabel.setForeground(Color.RED);
return false;
}
if (!authController.isUsernameAvailable(username)) {
resultLabel.setText("该用户名已存在");
resultLabel.setForeground(Color.RED);
return false;
}
if (!password.equals(confirmPassword)) {
resultLabel.setText("两次输入的密码不一致");
resultLabel.setForeground(Color.RED);
return false;
}
return true;
} }
private class SubmitAction implements ActionListener { private class SubmitAction implements ActionListener {
@ -84,34 +120,20 @@ public class PasswordSetupFrame extends JFrame {
public void actionPerformed(ActionEvent e) { public void actionPerformed(ActionEvent e) {
String password = new String(passwordField.getPassword()); String password = new String(passwordField.getPassword());
String confirmPassword = new String(confirmPasswordField.getPassword()); String confirmPassword = new String(confirmPasswordField.getPassword());
String username = new String(usernameField.getText());
if (password.isEmpty() || confirmPassword.isEmpty()) { if (!examingTextField(password, confirmPassword, username)) {
resultLabel.setText("请填写所有字段");
resultLabel.setForeground(Color.RED);
return;
}
if (!password.equals(confirmPassword)) {
resultLabel.setText("两次输入的密码不一致");
resultLabel.setForeground(Color.RED);
return; return;
} }
if (authController.completeRegistration(email, username, password)) {
// 使用已验证的验证码完成注册
if (authController.completeRegistration(email, code, password)) {
JOptionPane.showMessageDialog( JOptionPane.showMessageDialog(
PasswordSetupFrame.this, "注册成功!", "成功", JOptionPane.INFORMATION_MESSAGE); PasswordSetupFrame.this, "注册成功!", "成功", JOptionPane.INFORMATION_MESSAGE);
// 自动登录并跳转到难度选择界面
if (authController.login(email, password)) { if (authController.login(email, password)) {
LevelSelectionFrame levelFrame = new LevelSelectionFrame(authController); LevelSelectionFrame levelFrame = new LevelSelectionFrame(authController);
levelFrame.setVisible(true); levelFrame.setVisible(true);
dispose(); dispose();
} else { } else {
// 如果自动登录失败,跳转到登录界面
LoginFrame loginFrame = new LoginFrame(); LoginFrame loginFrame = new LoginFrame();
loginFrame.setVisible(true); loginFrame.setVisible(true);
dispose(); dispose();
} }
} else { } else {

@ -56,6 +56,7 @@ public class QuestionCountFrame extends JFrame {
@Override @Override
public void windowClosing(WindowEvent e) { public void windowClosing(WindowEvent e) {
parentFrame.setVisible(true); parentFrame.setVisible(true);
setVisible(false);
} }
}); });
add(mainPanel); add(mainPanel);

@ -94,7 +94,7 @@ public class QuizFrame extends JFrame {
// 选项面板 // 选项面板
JPanel optionsPanel = new JPanel(new GridLayout(4, 1, 10, 10)); JPanel optionsPanel = new JPanel(new GridLayout(4, 1, 10, 10));
optionsPanel.setBorder( optionsPanel.setBorder(
BorderFactory.createTitledBorder(BorderFactory.createLineBorder(Color.GRAY), "请选择答案")); BorderFactory.createTitledBorder(BorderFactory.createLineBorder(Color.GRAY), "请选择答案"));
optionButtons = new JRadioButton[4]; optionButtons = new JRadioButton[4];
buttonGroup = new ButtonGroup(); buttonGroup = new ButtonGroup();
@ -108,11 +108,11 @@ public class QuizFrame extends JFrame {
final int index = i; final int index = i;
optionButtons[i].addActionListener( optionButtons[i].addActionListener(
e -> { e -> {
// 保存当前选择 // 保存当前选择
userSelections[currentDisplayIndex] = index; userSelections[currentDisplayIndex] = index;
System.out.println("用户选择: 第" + (currentDisplayIndex + 1) + "题 -> 选项" + index); System.out.println("用户选择: 第" + (currentDisplayIndex + 1) + "题 -> 选项" + index);
}); });
buttonGroup.add(optionButtons[i]); buttonGroup.add(optionButtons[i]);
optionsPanel.add(optionButtons[i]); optionsPanel.add(optionButtons[i]);
@ -161,16 +161,16 @@ public class QuizFrame extends JFrame {
} }
Question currentQuestion = allQuestions.get(currentDisplayIndex); Question currentQuestion = allQuestions.get(currentDisplayIndex);
questionNumberLabel.setText( questionNumberLabel.setText(
String.format("第 %d 题 / 共 %d 题", currentDisplayIndex + 1, totalQuestions)); String.format("第 %d 题 / 共 %d 题", currentDisplayIndex + 1, totalQuestions));
questionTextLabel.setText( questionTextLabel.setText(
"<html><div style='text-align: center;'>" "<html><div style='text-align: center;'>"
+ currentQuestion.getQuestionText() + currentQuestion.getQuestionText()
+ "</div></html>"); + "</div></html>");
String[] options = currentQuestion.getOptions(); String[] options = currentQuestion.getOptions();
for (int i = 0; i < 4; i++) { for (int i = 0; i < 4; i++) {
String optionText = String optionText =
String.format( String.format(
"<html><div style='padding: 5px;'>%c. %s</div></html>", (char) ('A' + i), options[i]); "<html><div style='padding: 5px;'>%c. %s</div></html>", (char) ('A' + i), options[i]);
optionButtons[i].setText(optionText); optionButtons[i].setText(optionText);
} }
buttonGroup.clearSelection(); // 清除当前选择状态 buttonGroup.clearSelection(); // 清除当前选择状态
@ -184,17 +184,17 @@ public class QuizFrame extends JFrame {
// 更新进度条 // 更新进度条
progressBar.setValue(currentDisplayIndex); progressBar.setValue(currentDisplayIndex);
progressBar.setString( progressBar.setString(
String.format( String.format(
"%d/%d (%.0f%%)", "%d/%d (%.0f%%)",
currentDisplayIndex, currentDisplayIndex,
totalQuestions, totalQuestions,
((double) currentDisplayIndex / totalQuestions) * 100)); ((double) currentDisplayIndex / totalQuestions) * 100));
updateButtonStates(); // 更新按钮状态 updateButtonStates(); // 更新按钮状态
} }
private void exitQuiz() { private void exitQuiz() {
int result = int result =
JOptionPane.showConfirmDialog(this, "确定要退出答题吗?所有进度将丢失。", "退出确认", JOptionPane.YES_NO_OPTION); JOptionPane.showConfirmDialog(this, "确定要退出答题吗?所有进度将丢失。", "退出确认", JOptionPane.YES_NO_OPTION);
if (result == JOptionPane.YES_OPTION) { if (result == JOptionPane.YES_OPTION) {
parentFrame.setVisible(true); parentFrame.setVisible(true);
this.dispose(); this.dispose();
@ -238,8 +238,8 @@ public class QuizFrame extends JFrame {
// 如果没有选择答案,提示用户但允许继续(除了最后一题) // 如果没有选择答案,提示用户但允许继续(除了最后一题)
if (selectedIndex == -1) { if (selectedIndex == -1) {
int result = int result =
JOptionPane.showConfirmDialog( JOptionPane.showConfirmDialog(
QuizFrame.this, "您还没有选择答案,确定要继续下一题吗?", "确认", JOptionPane.YES_NO_OPTION); QuizFrame.this, "您还没有选择答案,确定要继续下一题吗?", "确认", JOptionPane.YES_NO_OPTION);
if (result != JOptionPane.YES_OPTION) { if (result != JOptionPane.YES_OPTION) {
return; return;
} }
@ -274,8 +274,9 @@ public class QuizFrame extends JFrame {
private void finishQuiz() { private void finishQuiz() {
// 使用原有的构造函数 // 使用原有的构造函数
ScoreFrame scoreFrame = new ScoreFrame(questionController, userSelections, allQuestions, parentFrame); ScoreFrame scoreFrame =
new ScoreFrame(questionController, userSelections, allQuestions, parentFrame);
scoreFrame.setVisible(true); scoreFrame.setVisible(true);
this.dispose(); this.dispose();
} }
} // 添加这个闭合大括号 } // 添加这个闭合大括号

@ -13,10 +13,10 @@ public class ScoreFrame extends JFrame {
private LevelSelectionFrame parentFrame; private LevelSelectionFrame parentFrame;
public ScoreFrame( public ScoreFrame(
QuestionController questionController, QuestionController questionController,
int[] userSelections, int[] userSelections,
List<Question> allQuestions, List<Question> allQuestions,
LevelSelectionFrame parent) { LevelSelectionFrame parent) {
this.parentFrame = parent; this.parentFrame = parent;
this.questionController = questionController; this.questionController = questionController;
this.userSelections = userSelections; this.userSelections = userSelections;
@ -40,7 +40,7 @@ public class ScoreFrame extends JFrame {
double percentage = (double) score / total * 100; // 手动计算百分比 double percentage = (double) score / total * 100; // 手动计算百分比
JLabel scoreLabel = JLabel scoreLabel =
new JLabel(String.format("得分: %d/%d (%.1f%%)", score, total, percentage), JLabel.CENTER); new JLabel(String.format("得分: %d/%d (%.1f%%)", score, total, percentage), JLabel.CENTER);
scoreLabel.setFont(new Font("Microsoft YaHei", Font.BOLD, 24)); scoreLabel.setFont(new Font("Microsoft YaHei", Font.BOLD, 24));
Color color; Color color;
@ -67,17 +67,15 @@ public class ScoreFrame extends JFrame {
details.append(String.format("第%d题: %s\n", i + 1, q.getQuestionText())); details.append(String.format("第%d题: %s\n", i + 1, q.getQuestionText()));
details.append( details.append(
String.format( String.format(
"你的答案: %s\n", "你的答案: %s\n",
userAnswer == -1 userAnswer == -1
? "未作答" ? "未作答"
: (char) ('A' + userAnswer) + ". " + q.getOptions()[userAnswer])); : (char) ('A' + userAnswer) + ". " + q.getOptions()[userAnswer]));
details.append( details.append(
String.format( String.format(
"正确答案: %s\n", "正确答案: %s\n",
(char) ('A' + q.getCorrectIndex()) (char) ('A' + q.getCorrectIndex()) + ". " + q.getOptions()[q.getCorrectIndex()]));
+ ". "
+ q.getOptions()[q.getCorrectIndex()]));
details.append(isCorrect ? "✓ 正确\n" : "✗ 错误\n"); details.append(isCorrect ? "✓ 正确\n" : "✗ 错误\n");
details.append("--------------------\n"); details.append("--------------------\n");
} }
@ -109,4 +107,4 @@ public class ScoreFrame extends JFrame {
parentFrame.setVisible(true); parentFrame.setVisible(true);
this.dispose(); this.dispose();
} }
} }

Loading…
Cancel
Save