diff --git a/src/main/java/mathlearning/model/User.java b/src/main/java/mathlearning/model/User.java index 57b7887..6ee96a3 100644 --- a/src/main/java/mathlearning/model/User.java +++ b/src/main/java/mathlearning/model/User.java @@ -1,5 +1,7 @@ package mathlearning.model; +import com.fasterxml.jackson.databind.BeanProperty; + import java.time.LocalDateTime; public class User { @@ -9,6 +11,7 @@ public class User { private LocalDateTime registrationDate; private String verificationCode; private boolean verified; + private String type; public User() {} @@ -18,6 +21,7 @@ public class User { this.verificationCode = verificationCode; this.verified = false; this.registrationDate = LocalDateTime.now(); + this.type = null; } // Getters and setters @@ -38,4 +42,7 @@ public class User { public String getUsername() { return username; } public void setUsername(String username) {this.username = username; } + + public String getType() { return type; } + public void setType(String type) { this.type = type; } } diff --git a/src/main/java/mathlearning/service/EmailService.java b/src/main/java/mathlearning/service/EmailService.java index 86f5b0d..cc9dcec 100644 --- a/src/main/java/mathlearning/service/EmailService.java +++ b/src/main/java/mathlearning/service/EmailService.java @@ -19,7 +19,7 @@ public class EmailService { this.auth = auth; } - public boolean sendVerificationCode(String toEmail, String verificationCode) { + public boolean sendVerificationCode(String toEmail, String verificationCode, int flag) { try { Properties props = new Properties(); props.put("mail.smtp.host", host); @@ -38,12 +38,11 @@ public class EmailService { message.setFrom(new InternetAddress(username)); message.setRecipients(Message.RecipientType.TO, InternetAddress.parse(toEmail)); message.setSubject("数学学习软件 - 注册验证码"); + String emailContent=""; + + if (flag == 1) emailContent = registerContent(verificationCode); + else if (flag == 2) emailContent = resetPasswordContent(verificationCode); - String emailContent = "尊敬的用户:\n\n" + - "您的注册验证码是:" + verificationCode + "\n\n" + - "该验证码有效期为10分钟。\n\n" + - "如果您没有注册本软件,请忽略此邮件。\n\n" + - "数学学习软件团队"; message.setText(emailContent); @@ -54,4 +53,20 @@ public class EmailService { return false; } } + + public String registerContent(String verificationCode) { + return "尊敬的用户:\n\n" + + "您的注册验证码是:" + verificationCode + "\n\n" + + "该验证码有效期为10分钟。\n\n" + + "如果您没有注册本软件,请忽略此邮件。\n\n" + + "数学学习软件团队"; + } + + public String resetPasswordContent(String verificationCode) { + return "尊敬的用户:\n\n" + + "您的重置验证码是:" + verificationCode + "\n\n" + + "该验证码有效期为10分钟。\n\n" + + "如果您没有重置密码,请忽略此邮件。\n\n" + + "数学学习软件团队"; + } } diff --git a/src/main/java/mathlearning/service/MultipleChoiceGenerator/ComputingUnit.java b/src/main/java/mathlearning/service/MultipleChoiceGenerator/ComputingUnit.java new file mode 100644 index 0000000..33c4a37 --- /dev/null +++ b/src/main/java/mathlearning/service/MultipleChoiceGenerator/ComputingUnit.java @@ -0,0 +1,190 @@ + +package mathlearning.service.MultipleChoiceGenerator; + + +import java.util.ArrayList; +import java.util.List; +import java.util.Stack; + +public class ComputingUnit { + String expression; + Stack numbers = new Stack<>(); + Stack operators = new Stack<>(); + + ComputingUnit(String Question){ + expression = Question; + } + + private void SplitAndChange(){ + + String[] split = expression.split(" "); + split = separateParentheses(split); + for(int i = 0 ; i < split.length ; i++){ + if (split[i].charAt(0) == '√') { + String StrNum = split[i].substring(1); + double num = Math.sqrt(Double.parseDouble(StrNum)); + split[i] = String.valueOf(num); + } else if (split[i].charAt(split[i].length()-1) == '²') { + String StrNum = split[i].substring(0, split[i].length()-1); + double result = Math.pow(Double.parseDouble(StrNum), 2); + split[i] = String.valueOf(result); + } else if ((split[i].charAt(0) == 's' || split[i].charAt(0) == 'c' + || split[i].charAt(0) == 't' )) { + int index = split[i].indexOf(')'); + int index2 = split[i].indexOf('('); + String StrNum = split[i].substring(index2 + 1, index); + double num = Double.parseDouble(SquOrRoot(StrNum)); + double result = getFunc(split[i].charAt(0), num); + split[i] = String.valueOf(result); + } + } + this.expression = String.join(" ", split); + } + + public String[] separateParentheses(String[] originalArray) { + List result = new ArrayList<>(); + + for (String item : originalArray) { + if (item.startsWith("(") && item.length() > 1) { + // 如果字符串以(开头且长度大于1,分离出( + result.add("("); + result.add(item.substring(1).trim()); + } else if (item.endsWith(")") && item.length() > 1 && + (item.charAt(0) != 's' && item.charAt(0) != 'c' && item.charAt(0) != 't')) { + // 如果字符串以)结尾且长度大于1,分离出) + result.add(item.substring(0, item.length() - 1).trim()); + result.add(")"); + } else if ((item.charAt(0) == 's' || item.charAt(0) == 'c' || item.charAt(0) == 't') && + (item.endsWith(")") && item.charAt(item.length()-2) == ')')) { + result.add(item.substring(0, item.length() - 1).trim()); + result.add(")"); + } else { + // 其他情况保持不变 + result.add(item); + } + } + + return result.toArray(new String[0]); + } + + + private String SquOrRoot(String StrNum){ + if(StrNum.charAt(0) == '√'){ + return String.valueOf(Math.sqrt(Double.parseDouble(StrNum.substring(1)))); + } else if (StrNum.charAt(StrNum.length()-1) == '²') { + return String.valueOf(Math.pow(Double.parseDouble(StrNum.substring(0, StrNum.length()-1)), 2)); + }else { + return StrNum; + } + } + + private double getFunc(char func, double num){ + switch (func) { + case 's': + return Math.sin(num); + case 'c': + return Math.cos(num); + case 't': + return Math.tan(num); + default: + return 0; + } + } + + private void priority(String operator){ + if(operators.isEmpty() || operators.peek().equals("(")){ + operators.push(operator); + }else{ + if((operators.peek().equals("+")|| operators.peek().equals("-")) && + (operator.equals("×") || operator.equals("÷"))){ + operators.push(operator); + }else{ + CulAndPushOperator(operator); + } + } + } + + private void CulAndPushOperator(String operator){ + String num1 = numbers.pop(); + String num2 = numbers.pop(); + String operator1 = operators.pop(); + operators.push(operator); + String result = SingleCul(num2, operator1, num1); + numbers.push(result); + } + + private String Compute(){ + String[] spilt = expression.split(" "); + for (int i = 0; i < spilt.length; i++){ + if(spilt[i].equals("+") || spilt[i].equals("-") || + spilt[i].equals("×") || spilt[i].equals("÷") || + spilt[i].equals("(") ){//处理运算符 + if( spilt[i].equals("(")){ + operators.push(spilt[i]); + }else{ + priority(spilt[i]); + } + }else if(spilt[i].equals(")")){ + String tempResult = numbers.pop(); + while (!operators.peek().equals("(")){ + String operator = operators.pop(); + String num1 = numbers.pop(); + tempResult = SingleCul(num1, operator, tempResult); + } + if(operators.peek().equals("(")){ + operators.pop(); + } + numbers.push(tempResult); + } else { + numbers.push(spilt[i]); + } + } + return CulWithoutPriority(); + } + + private String CulWithoutPriority(){ + if(numbers.isEmpty()){ + return "0"; + } + String result = numbers.pop(); + while (!operators.isEmpty() && !numbers.isEmpty()){ + String num1 = numbers.pop(); + String operator = operators.pop(); + result = SingleCul(num1, operator, result); + } + return result; + } + + public String getAnswer(){ + SplitAndChange(); + return Compute(); + } + + private String SingleCul(String nowResult, String operator, String num){ + // 使用 trim() 去除首尾空格 + // 使用 split("\\s+") 按空格分割,只取第一个元素(数字) + String cleanNowResult = nowResult.trim().split("\\s+")[0]; + String cleanNum = num.trim().split("\\s+")[0]; + + // 现在可以安全地解析数字了 + Double result = Double.parseDouble(cleanNowResult); + switch (operator) { + case "+": + result += Double.parseDouble(cleanNum); + break; + case "-": + result -= Double.parseDouble(cleanNum); + break; + case "×": + result *= Double.parseDouble(cleanNum); + break; + case "÷": + result /= Double.parseDouble(cleanNum); + break; + } + return String.valueOf(result); + } + + +} + diff --git a/src/main/java/mathlearning/service/MultipleChoiceGenerator/MultipleChoiceGenerator.java b/src/main/java/mathlearning/service/MultipleChoiceGenerator/MultipleChoiceGenerator.java new file mode 100644 index 0000000..bac03e3 --- /dev/null +++ b/src/main/java/mathlearning/service/MultipleChoiceGenerator/MultipleChoiceGenerator.java @@ -0,0 +1,92 @@ +package mathlearning.service.MultipleChoiceGenerator; +import mathlearning.model.User; +import mathlearning.service.QuestionGenerator.*; + +import java.util.*; + +public class MultipleChoiceGenerator { + private static QuestionGenerator QuestionGenerator = new PrimaryGenerator(); + String[] QuestionList ; + String[] AnswerList ; + String[] ChoiceList ; + + MultipleChoiceGenerator(int count, User nowUser){// 如此声明MultipleChoiceGenerator实例,再调用下面三个接口 + this.QuestionList = new String[count]; + this.ChoiceList = new String[count]; + this.QuestionList = SetQuestionList(count, nowUser); + SetChoiceList(); + } + + public String[] GetQuestionList(){ + return this.QuestionList; + } + + public String[] GetChoiceList(){ + return this.ChoiceList; + } + + public String[] GetAnswerList(){ + return this.AnswerList; + } + + private void SetChoiceList(){ + for(int i = 0 ; i < this.AnswerList.length ; i++){ + Random random = new Random(); + String[] choiceNo = {"A.","B.","C.","D."}; + String[] choices = new String[4]; + double correctChoice = Double.parseDouble(this.AnswerList[i]); + int position = random.nextInt(4); + choices[position] = choiceNo[position] + String.format("%.2f", correctChoice); + + + for(int j = 0 ; j < 4 ; j++){ + if(j != position){ + double choice = correctChoice; + double offset = random.nextInt(41) - 20; + choice += offset; + choices[j] =choiceNo[j] + String.format("%.2f", choice); + } + } + + this.ChoiceList[i] = String.join("\n", choices); + } + } + + private String[] SetQuestionList(int count, User nowUser){ + String[] Questions= new String[count]; + if(nowUser.getType().equals("小学") ) { + QuestionGenerator = new PrimaryGenerator(); + } + else if( nowUser.getType().equals("初中") ) { + QuestionGenerator = new middleGenerator(); + } + else if( nowUser.getType().equals("高中") ) { + QuestionGenerator = new highGenerator(); + } + + List questions = new ArrayList<>(); + Set generatedQuestions = new HashSet<>(); + + for (int i = 0; i < count; i++) { + String question; + do { + question = QuestionGenerator.generateQuestion(); + } while ( generatedQuestions.contains(question )); + generatedQuestions.add(question); + questions.add(question); + } + + for(int i = 0 ; i< count ; i++){ + Questions[i] = questions.get(i); + } + this.AnswerList = new String[count]; + for(int i = 0 ; i< count ; i++){ + ComputingUnit computingUnit = new ComputingUnit(Questions[i]); + this.AnswerList[i] = computingUnit.getAnswer(); + } + return Questions; + } + + + +} diff --git a/src/main/java/mathlearning/service/MultipleChoiceGenerator/MultipleChoiceGeneratorTest.java b/src/main/java/mathlearning/service/MultipleChoiceGenerator/MultipleChoiceGeneratorTest.java new file mode 100644 index 0000000..260dd42 --- /dev/null +++ b/src/main/java/mathlearning/service/MultipleChoiceGenerator/MultipleChoiceGeneratorTest.java @@ -0,0 +1,37 @@ +package mathlearning.service.MultipleChoiceGenerator; + +import mathlearning.model.User; + +public class MultipleChoiceGeneratorTest { + public static void main(String[] args) { + // 创建一个模拟用户 + User testUser = new User(); + testUser.setType("小学"); // 可以分别测试"小学"、"初中"、"高中" + + // 测试生成10道题目 + int questionCount = 10; + MultipleChoiceGenerator generator = new MultipleChoiceGenerator(questionCount, testUser); + + // 获取生成的题目、答案和选项 + String[] questions = generator.GetQuestionList(); + String[] answers = generator.GetAnswerList(); + String[] choices = generator.GetChoiceList(); + + // 输出测试结果 + System.out.println("=== 数学题目生成测试 ==="); + System.out.println("用户类型: " + testUser.getType()); + System.out.println("生成题目数量: " + questionCount); + System.out.println(); + + for (int i = 0; i < questions.length; i++) { + System.out.println("题目 " + (i + 1) + ": " + questions[i]); + System.out.println("答案: " + answers[i]); + System.out.println("选项:"); + String[] choiceArray = choices[i].split("\n"); + for (int j = 0; j < choiceArray.length; j++) { + System.out.println(" " + (char)('A' + j) + ". " + choiceArray[j]); + } + System.out.println("----------------------------------------"); + } + } +} diff --git a/src/main/java/mathlearning/service/QuestionGenerator/PrimaryGenerator.java b/src/main/java/mathlearning/service/QuestionGenerator/PrimaryGenerator.java new file mode 100644 index 0000000..d4f73fc --- /dev/null +++ b/src/main/java/mathlearning/service/QuestionGenerator/PrimaryGenerator.java @@ -0,0 +1,22 @@ +package mathlearning.service.QuestionGenerator; + +public class PrimaryGenerator extends QuestionGenerator{ + public PrimaryGenerator() { + super("小学"); + } + + @Override + public String generateQuestion() { + + int operandCount = random.nextInt(4) + 2; + + // 生成操作数 + int[] operands = new int[operandCount]; + for (int i = 0; i < operandCount; i++) { + operands[i] = random.nextInt(100) + 1; // 1-100 + } + + String question = preForOper(operands); + return addParen(question); + } +} diff --git a/src/main/java/mathlearning/service/QuestionGenerator/QuestionGenerator.java b/src/main/java/mathlearning/service/QuestionGenerator/QuestionGenerator.java new file mode 100644 index 0000000..b41d315 --- /dev/null +++ b/src/main/java/mathlearning/service/QuestionGenerator/QuestionGenerator.java @@ -0,0 +1,142 @@ +package mathlearning.service.QuestionGenerator; + +import java.util.Random; + +public abstract class QuestionGenerator{ + protected Random random = new Random(); + public abstract String generateQuestion() ; + protected String type; + + public String getType() { + return type; + } + + QuestionGenerator() { + type = "无"; + } + + QuestionGenerator(String Type) { + type = Type; + } + + protected String preForOper(int[] operands) { + StringBuilder question = new StringBuilder(); + String[] operators = {"+", "-", "×", "÷"}; + question.append(operands[0]); + + for (int i = 1; i < operands.length; i++) { + String op = operators[ random.nextInt (operators.length)]; + question.append(" ").append(op).append(" ").append(operands[i]); + } + return question.toString(); + + } + + protected boolean Check_num(String expression) { + if(!(expression.equals("+") || expression.equals("-") || expression.equals("×") || expression.equals("÷"))) { + return true; + } + else{ + return false; + } + } + + protected String addParen(String expression) { + String[] parts = expression.split(" "); + StringBuilder result = new StringBuilder(); + boolean r_paren_needed = false; + + for (int i = 0; i < parts.length; i++) { + if(Check_num ( parts [i]) ) { + if( !r_paren_needed ) { + if(i <= parts.length -3 ) + { + if( random.nextBoolean() ) + { result.append("(");r_paren_needed = true;} + } + result.append(parts[i]); + } else { + result.append( parts [i]); + if( !random.nextBoolean()) { + result.append(")");r_paren_needed = false; + } + } + } else { + result.append( parts [i] ); + } + if( i < parts.length -1 ) { + result.append(" "); + } + } + + if( r_paren_needed ){ + result.append(")");r_paren_needed = false; + } + return result.toString(); + } + + protected String add_squs(String expression) { + String[] parts = expression.split(" "); + StringBuilder result = new StringBuilder(); + boolean has_squs = false; + + for (int i = 0; i < parts.length; i++) { + if( Check_num( parts [i] )) { + double Thres = 0.3; + if( !has_squs){ + Thres = 0.7; + } + if ( random.nextDouble() < Thres ||(i == parts.length -1 && !has_squs)) { + if ( random.nextBoolean() ) { + result.append(parts[i]); + result.append("²"); + has_squs = true; + } else { + result.append("√"); + result.append(parts[i]); + has_squs = true; + } + } else { + result.append(parts[i]); + } + } else { + result.append(parts[i]); + } + if( i < parts.length -1 ) { + result.append(" "); + } + } + return result.toString(); + } + + protected String add_sins(String expression) { + String[] parts = expression.split(" "); + StringBuilder result = new StringBuilder(); + String[] functions = {"sin", "cos", "tan"}; + boolean has_func = false; + + for (int i = 0; i < parts.length; i++) { + double Thres = 0.4; + if(!has_func){Thres = 0.8;} + if(Check_num(parts[i])) + { + if ( random.nextDouble() < Thres ||(i == parts.length-1 && !has_func) ) { + String func = functions[random.nextInt(functions.length)]; + result.append(func).append("(").append(parts[i]).append(")"); + } else { + result.append(parts[i]); + } + } else { + result.append(parts[i]); + } + if( i < parts.length-1 ) { + result.append(" "); + } + + } + + return result.toString(); + } +} + + diff --git a/src/main/java/mathlearning/service/QuestionGenerator/highGenerator.java b/src/main/java/mathlearning/service/QuestionGenerator/highGenerator.java new file mode 100644 index 0000000..bfc17fc --- /dev/null +++ b/src/main/java/mathlearning/service/QuestionGenerator/highGenerator.java @@ -0,0 +1,24 @@ +package mathlearning.service.QuestionGenerator; + +public class highGenerator extends QuestionGenerator{ + + public highGenerator() { + super("高中"); + } + + @Override + public String generateQuestion() { + int operandCount = random.nextInt(4) + 2; + + // 生成操作数 + int[] operands = new int[ operandCount ]; + for (int i = 0; i < operandCount; i++) { + operands[i] = random.nextInt(100) + 1; // 1-100 + } + + String question = preForOper( operands ); + question = add_squs( question ); + question = add_sins( question ); + return addParen( question ); + } +} diff --git a/src/main/java/mathlearning/service/QuestionGenerator/middleGenerator.java b/src/main/java/mathlearning/service/QuestionGenerator/middleGenerator.java new file mode 100644 index 0000000..b1d3b61 --- /dev/null +++ b/src/main/java/mathlearning/service/QuestionGenerator/middleGenerator.java @@ -0,0 +1,23 @@ +package mathlearning.service.QuestionGenerator; + +public class middleGenerator extends QuestionGenerator{ + + public middleGenerator() { + super("初中"); + } + + @Override + public String generateQuestion() { + int operandCount = random.nextInt(4) + 2; + + // 生成操作数 + int[] operands = new int [ operandCount ]; + for (int i = 0; i < operandCount; i++) { + operands[i] = random.nextInt(100) + 1; // 1-100 + } + + String question = preForOper(operands); + question = add_squs(question); + return addParen(question); + } +} \ No newline at end of file diff --git a/src/main/java/mathlearning/service/UserService.java b/src/main/java/mathlearning/service/UserService.java index f239562..f9c0c95 100644 --- a/src/main/java/mathlearning/service/UserService.java +++ b/src/main/java/mathlearning/service/UserService.java @@ -147,6 +147,58 @@ public class UserService { return true; } + public boolean setPasswordResetCode(String email, String verificationCode) { + User user = users.get(email); + if (user == null) { + return false; // 用户不存在 + } + + user.setVerificationCode(verificationCode); + verificationCodeTimestamps.put(email, LocalDateTime.now()); + saveUsers(); + return true; + } + + public boolean resetPasswordWithCode(String email, String verificationCode, String newPassword) { + User user = users.get(email); + if (user == null) { + return false; + } + + // 验证验证码 + if (!user.getVerificationCode().equals(verificationCode)) { + return false; + } + + // 检查验证码是否过期 + LocalDateTime codeTime = verificationCodeTimestamps.get(email); + if (codeTime == null || codeTime.plusMinutes(VERIFICATION_CODE_EXPIRY_MINUTES).isBefore(LocalDateTime.now())) { + return false; + } + + // 验证新密码格式 + if (!validatePassword(newPassword)) { + return false; + } + + // 更新密码 + String newPasswordHash = BCrypt.withDefaults().hashToString(12, newPassword.toCharArray()); + user.setPasswordHash(newPasswordHash); + verificationCodeTimestamps.remove(email); // 清除验证码 + saveUsers(); + return true; + } + + public boolean updateUserType(String email, String type) { + User user = users.get(email); + if (user == null) { + return false; + } + user.setType(type); + saveUsers(); + return true; + } + public boolean validatePassword(String password) { if (password.length() < 6 || password.length() > 10) { return false; @@ -169,7 +221,17 @@ public class UserService { return users.containsKey(email); } + public boolean isUserExistsAndVerified(String email) { + User user = users.get(email); + return user != null && user.isVerified(); + } + public boolean isValidEmail(String email) { return email.matches("^[A-Za-z0-9+_.-]+@(.+)$"); } + + public User getUser(String email ) { + User user = users.get(email); + return user; + } } \ No newline at end of file diff --git a/src/main/java/mathlearning/ui/ChangeCodeFrame.java b/src/main/java/mathlearning/ui/ChangeCodeFrame.java new file mode 100644 index 0000000..1255136 --- /dev/null +++ b/src/main/java/mathlearning/ui/ChangeCodeFrame.java @@ -0,0 +1,221 @@ +package mathlearning.ui; + +import mathlearning.service.EmailService; +import mathlearning.service.UserService; + +import javax.swing.*; +import java.awt.*; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; + +public class ChangeCodeFrame extends JFrame { + private UserService userService; + private EmailService emailService; + private LoginFrame loginFrame; + + private JTextField emailField; + private JButton sendCodeButton; + private JTextField codeField; + private JPasswordField passwordField; + private JPasswordField confirmPasswordField; + private JButton registerButton; + private JButton backButton; + + private String verificationCode; + + public ChangeCodeFrame(UserService userService, LoginFrame loginFrame) { + this.userService = userService; + this.loginFrame = loginFrame; + + // 配置邮箱服务(需要替换为真实的邮箱配置) + this.emailService = new EmailService( + "smtp.qq.com", + "587", + "2793415226@qq.com", // 替换为你的QQ邮箱 + "rmiomlakglpjddhb", // 替换为你的授权码 + true + ); + + initializeUI(); + } + + private void initializeUI() { + setTitle("数学学习软件 - 忘记密码"); + setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + setSize(450, 400); + setLocationRelativeTo(null); + setResizable(false); + + // 主面板 + JPanel mainPanel = new JPanel(new BorderLayout(10, 10)); + mainPanel.setBorder(BorderFactory.createEmptyBorder(20, 20, 20, 20)); + + // 标题 + JLabel titleLabel = new JLabel("重置密码", JLabel.CENTER); + titleLabel.setFont(new Font("微软雅黑", Font.BOLD, 24)); + mainPanel.add(titleLabel, BorderLayout.NORTH); + + //表单面板 + JPanel formPanel = new JPanel(new GridLayout(5, 2, 10, 10)); + + JLabel emailLabel = new JLabel("邮箱:"); + emailLabel.setFont(new Font("微软雅黑", Font.PLAIN, 14)); + emailField = new JTextField(); + + JLabel codeLabel = new JLabel("验证码:"); + codeLabel.setFont(new Font("微软雅黑", Font.PLAIN, 14)); + + JPanel codePanel = new JPanel(new BorderLayout()); + codeField = new JTextField(); + sendCodeButton = new JButton("发送验证码"); + sendCodeButton.addActionListener(new SendCodeListener()); + + codePanel.add(codeField, BorderLayout.CENTER); + codePanel.add(sendCodeButton, BorderLayout.EAST); + + JLabel passwordLabel = new JLabel("新密码:"); + passwordLabel.setFont(new Font("微软雅黑", Font.PLAIN, 14)); + passwordField = new JPasswordField(); + + JLabel confirmPasswordLabel = new JLabel("确认密码:"); + confirmPasswordLabel.setFont(new Font("微软雅黑", Font.PLAIN, 14)); + confirmPasswordField = new JPasswordField(); + + formPanel.add(emailLabel); + formPanel.add(emailField); + formPanel.add(codeLabel); + formPanel.add(codePanel); + formPanel.add(passwordLabel); + formPanel.add(passwordField); + formPanel.add(confirmPasswordLabel); + formPanel.add(confirmPasswordField); + + mainPanel.add(formPanel, BorderLayout.CENTER); + + // 按钮面板 + JPanel buttonPanel = new JPanel(new FlowLayout()); + + registerButton = new JButton("更改密码"); + registerButton.setFont(new Font("微软雅黑", Font.PLAIN, 14)); + registerButton.addActionListener(new ChangeCodeFrame.ChangeCodeButtonListener()); + + backButton = new JButton("返回登录"); + backButton.setFont(new Font("微软雅黑", Font.PLAIN, 14)); + backButton.addActionListener(e -> goBackToLogin()); + + buttonPanel.add(registerButton); + buttonPanel.add(backButton); + + mainPanel.add(buttonPanel, BorderLayout.SOUTH); + + add(mainPanel); + } + + private class SendCodeListener implements ActionListener { + @Override + public void actionPerformed(ActionEvent e) { + String email = emailField.getText().trim(); + + if (email.isEmpty()) { + JOptionPane.showMessageDialog(ChangeCodeFrame.this, + "请输入邮箱地址", "错误", JOptionPane.ERROR_MESSAGE); + return; + } + + if (!userService.isValidEmail(email)) { + JOptionPane.showMessageDialog(ChangeCodeFrame.this, + "邮箱格式不正确", "错误", JOptionPane.ERROR_MESSAGE); + return; + } + + // 检查用户是否存在且已验证 + if (!userService.isUserExistsAndVerified(email)) { + JOptionPane.showMessageDialog(ChangeCodeFrame.this, + "该邮箱未注册或未验证", "错误", JOptionPane.ERROR_MESSAGE); + return; + } + + // 生成6位验证码 + verificationCode = String.valueOf((int)((Math.random() * 9 + 1) * 100000)); + + // 发送验证码邮件 + boolean sent = emailService.sendVerificationCode(email, verificationCode, 2); + + if (sent) { + // 在服务中保存验证码 + boolean codeSaved = userService.setPasswordResetCode(email, verificationCode); + + if (codeSaved) { + JOptionPane.showMessageDialog(ChangeCodeFrame.this, + "验证码已发送到您的邮箱,请查收", "成功", JOptionPane.INFORMATION_MESSAGE); + + // 禁用发送按钮60秒 + sendCodeButton.setEnabled(false); + new Thread(() -> { + try { + for (int i = 60; i > 0; i--) { + final int current = i; + SwingUtilities.invokeLater(() -> + sendCodeButton.setText(current + "秒后重发")); + Thread.sleep(1000); + } + SwingUtilities.invokeLater(() -> { + sendCodeButton.setText("发送验证码"); + sendCodeButton.setEnabled(true); + }); + } catch (InterruptedException ex) { + ex.printStackTrace(); + } + }).start(); + } else { + JOptionPane.showMessageDialog(ChangeCodeFrame.this, + "保存验证码失败", "错误", JOptionPane.ERROR_MESSAGE); + } + } else { + JOptionPane.showMessageDialog(ChangeCodeFrame.this, + "验证码发送失败,请检查邮箱地址或网络连接", "错误", JOptionPane.ERROR_MESSAGE); + } + } + } + + private class ChangeCodeButtonListener implements ActionListener { + @Override + public void actionPerformed(ActionEvent e) { + String email = emailField.getText().trim(); + String code = codeField.getText().trim(); + String password = new String(passwordField.getPassword()); + String confirmPassword = new String(confirmPasswordField.getPassword()); + + // 验证输入 + if (email.isEmpty() || code.isEmpty() || password.isEmpty()) { + JOptionPane.showMessageDialog(ChangeCodeFrame.this, + "请填写所有字段", "错误", JOptionPane.ERROR_MESSAGE); + return; + } + if (!password.equals(confirmPassword)) { + JOptionPane.showMessageDialog(ChangeCodeFrame.this, + "两次输入的密码不一致", "错误", JOptionPane.ERROR_MESSAGE); + return; + } + if (!userService.validatePassword(password)) { + JOptionPane.showMessageDialog(ChangeCodeFrame.this, + "密码必须为6-10位,且包含大小写字母和数字", "错误", JOptionPane.ERROR_MESSAGE); + return; + } + + if (userService.resetPasswordWithCode(email, code, password)) { + JOptionPane.showMessageDialog(ChangeCodeFrame.this, + "密码重置成功!", "成功", JOptionPane.INFORMATION_MESSAGE); + goBackToLogin(); + } else { + JOptionPane.showMessageDialog(ChangeCodeFrame.this, + "重置失败,请检查验证码是否正确或是否已过期", "错误", JOptionPane.ERROR_MESSAGE); + } + } + } + + private void goBackToLogin() { + loginFrame.setVisible(true); + this.dispose(); + } +} diff --git a/src/main/java/mathlearning/ui/LoginFrame.java b/src/main/java/mathlearning/ui/LoginFrame.java index a9579d0..b6d00b0 100644 --- a/src/main/java/mathlearning/ui/LoginFrame.java +++ b/src/main/java/mathlearning/ui/LoginFrame.java @@ -63,8 +63,13 @@ public class LoginFrame extends JFrame{ registerButton.setFont(new Font("微软雅黑", Font.PLAIN, 14)); registerButton.addActionListener(e -> openRegisterFrame()); + JButton changeCodeButton = new JButton("忘记密码?"); + changeCodeButton.setFont(new Font("微软雅黑", Font.PLAIN, 14)); + changeCodeButton.addActionListener(e -> openChangeCodeFrame()); + buttonPanel.add(loginButton); buttonPanel.add(registerButton); + buttonPanel.add(changeCodeButton); mainPanel.add(buttonPanel, BorderLayout.SOUTH); @@ -101,11 +106,57 @@ public class LoginFrame extends JFrame{ this.setVisible(false); } + private void openChangeCodeFrame() { + ChangeCodeFrame changeCodeFrame = new ChangeCodeFrame(userService, this); + changeCodeFrame.setVisible(true); + this.setVisible(false); + } + private void openMainFrame(String email) { + User user = userService.getUser(email); + // 如果用户类型为空,让用户选择类型 + if (user.getType() == null || user.getType().isEmpty()) { + String[] types = {"小学", "初中", "高中"}; + String selectedType = (String) JOptionPane.showInputDialog( + this, + "欢迎 " + user.getUsername() + "!\n请选择您的教育阶段:", + "选择教育阶段", + JOptionPane.QUESTION_MESSAGE, + null, + types, + types[0] // 默认选择第一个 + ); + + // 如果用户选择了类型(没有点击取消) + if (selectedType != null) { + // 更新用户类型 + boolean updated = userService.updateUserType(email, selectedType); + if (updated) { + // 更新本地user对象 + user.setType(selectedType); + JOptionPane.showMessageDialog(this, + "登录成功!\n教育阶段:" + selectedType, + "登录成功", JOptionPane.INFORMATION_MESSAGE); + } else { + JOptionPane.showMessageDialog(this, + "登录成功!\n但教育阶段设置失败", + "登录成功", JOptionPane.WARNING_MESSAGE); + } + } else { + // 如果用户取消选择,可以设置默认类型或者保持为空 + userService.updateUserType(email, "小学"); + user.setType("小学"); + JOptionPane.showMessageDialog(this, + "登录成功!\n已为您选择默认教育阶段:小学", + "登录成功", JOptionPane.INFORMATION_MESSAGE); + } + } else { + // 如果已经有类型,直接显示欢迎信息 + JOptionPane.showMessageDialog(this, + "欢迎 " + user.getUsername() + "!\n登录成功。\n教育阶段:" + user.getType(), + "登录成功", JOptionPane.INFORMATION_MESSAGE); + } - // 这里先简单显示一个消息,后续可以扩展为主界面 - JOptionPane.showMessageDialog(this, - "欢迎 " + email + "!\n登录成功,主界面功能待实现。", - "登录成功", JOptionPane.INFORMATION_MESSAGE); + // openMainApplicationWindow(user); } } diff --git a/src/main/java/mathlearning/ui/MainFrame.java b/src/main/java/mathlearning/ui/MainFrame.java new file mode 100644 index 0000000..abf8743 --- /dev/null +++ b/src/main/java/mathlearning/ui/MainFrame.java @@ -0,0 +1,53 @@ +package mathlearning.ui; + +import mathlearning.model.User; +import mathlearning.service.UserService; + +import javax.swing.*; +import java.awt.*; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; + +public class MainFrame extends JFrame { + private User currentUser; + private UserService userService; + private JLabel welcomeLabel; + + public MainFrame(User user, UserService userService) { + this.currentUser = user; + this.userService = userService; + InitializeUI(); + } + + private void InitializeUI() { + setTitle("数学学习软件 - 菜单"); + setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + setSize(500, 400); + setLocationRelativeTo(null); + setResizable(false); + + // 主面板 + JPanel titlePanel = new JPanel(new BorderLayout()); + JPanel mainPanel = new JPanel(new BorderLayout(10, 10)); + mainPanel.setBorder(BorderFactory.createEmptyBorder(20, 20, 20, 20)); + + // 欢迎用户与type信息 + welcomeLabel = new JLabel("欢迎"+currentUser.getUsername()+"!", JLabel.CENTER); + welcomeLabel.setFont(new Font("微软雅黑", Font.BOLD, 24)); + + JLabel typeLabel = new JLabel("当前选择的测试题为" + currentUser.getType() + "难度", JLabel.CENTER); + typeLabel.setFont(new Font("微软雅黑", Font.BOLD, 16)); + typeLabel.setForeground(Color.BLUE); + + titlePanel.add(welcomeLabel, BorderLayout.NORTH); + titlePanel.add(typeLabel, BorderLayout.CENTER); + mainPanel.add(titlePanel, BorderLayout.NORTH); + + // 功能按钮区域 + JPanel centerButtonPanel = new JPanel(new GridLayout(2, 1, 15, 15)); + centerButtonPanel.setBorder(BorderFactory.createEmptyBorder(30, 50, 30, 50)); + + + + } +} diff --git a/src/main/java/mathlearning/ui/RegisterFrame.java b/src/main/java/mathlearning/ui/RegisterFrame.java index ebc97c7..b5fc993 100644 --- a/src/main/java/mathlearning/ui/RegisterFrame.java +++ b/src/main/java/mathlearning/ui/RegisterFrame.java @@ -145,7 +145,7 @@ public class RegisterFrame extends JFrame{ verificationCode = String.valueOf((int)((Math.random() * 9 + 1) * 100000)); // 发送验证码邮件 - boolean sent = emailService.sendVerificationCode(email, verificationCode); + boolean sent = emailService.sendVerificationCode(email, verificationCode, 1); if (sent) { JOptionPane.showMessageDialog(RegisterFrame.this,