diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..5ff6309
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,38 @@
+target/
+!.mvn/wrapper/maven-wrapper.jar
+!**/src/main/**/target/
+!**/src/test/**/target/
+
+### IntelliJ IDEA ###
+.idea/modules.xml
+.idea/jarRepositories.xml
+.idea/compiler.xml
+.idea/libraries/
+*.iws
+*.iml
+*.ipr
+
+### Eclipse ###
+.apt_generated
+.classpath
+.factorypath
+.project
+.settings
+.springBeans
+.sts4-cache
+
+### NetBeans ###
+/nbproject/private/
+/nbbuild/
+/dist/
+/nbdist/
+/.nb-gradle/
+build/
+!**/src/main/**/build/
+!**/src/test/**/build/
+
+### VS Code ###
+.vscode/
+
+### Mac OS ###
+.DS_Store
\ No newline at end of file
diff --git a/.idea/.gitignore b/.idea/.gitignore
new file mode 100644
index 0000000..359bb53
--- /dev/null
+++ b/.idea/.gitignore
@@ -0,0 +1,3 @@
+# 默认忽略的文件
+/shelf/
+/workspace.xml
diff --git a/.idea/.name b/.idea/.name
new file mode 100644
index 0000000..4f2c764
--- /dev/null
+++ b/.idea/.name
@@ -0,0 +1 @@
+UserService.java
\ No newline at end of file
diff --git a/.idea/encodings.xml b/.idea/encodings.xml
new file mode 100644
index 0000000..aa00ffa
--- /dev/null
+++ b/.idea/encodings.xml
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/misc.xml b/.idea/misc.xml
index 2bfdeda..0944a8f 100644
--- a/.idea/misc.xml
+++ b/.idea/misc.xml
@@ -1,6 +1,14 @@
-
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/vcs.xml b/.idea/vcs.xml
index 8306744..94a25f7 100644
--- a/.idea/vcs.xml
+++ b/.idea/vcs.xml
@@ -1,7 +1,6 @@
-
\ No newline at end of file
diff --git a/.idea/workspace.xml b/.idea/workspace.xml
index 1288078..72cf962 100644
--- a/.idea/workspace.xml
+++ b/.idea/workspace.xml
@@ -1,8 +1,30 @@
+
+
+
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -12,9 +34,9 @@
-
+ {
+ "associatedIndex": 8
+}
@@ -24,12 +46,26 @@
"keyToString": {
"ModuleVcsDetector.initialDetectionPerformed": "true",
"RunOnceActivity.ShowReadmeOnStart": "true",
+ "RunOnceActivity.TerminalTabsStorage.copyFrom.TerminalArrangementManager.252": "true",
"RunOnceActivity.git.unshallow": "true",
- "git-widget-placeholder": "liuxinrui__branch",
+ "git-widget-placeholder": "正在合并 liuxinrui__branch",
"kotlin-language-version-configured": "true",
"last_opened_file_path": "D:/filee/软导/java/结对/project/MathLearningApp/git"
}
}]]>
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -40,4 +76,19 @@
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/data/users.json b/data/users.json
new file mode 100644
index 0000000..721399b
--- /dev/null
+++ b/data/users.json
@@ -0,0 +1,17 @@
+[ {
+ "username" : "LXR",
+ "email" : "2759462569@qq.com",
+ "passwordHash" : "$2a$12$AiupZKqpZMXvstX6XYNGUuBDZOMdzqXy/ADaYzurUYatM293Lbxii",
+ "registrationDate" : [ 2025, 10, 11, 19, 40, 59, 177105400 ],
+ "verificationCode" : "371978",
+ "verified" : true,
+ "type" : "高中"
+}, {
+ "username" : "小鱼",
+ "email" : "1280556515@qq.com",
+ "passwordHash" : "$2a$12$dbNwBK6NBj7mXU6YzNMAweTMhD9NOxsjPGzW2SfIM.QvGdWt7Lyvy",
+ "registrationDate" : [ 2025, 10, 10, 11, 7, 5, 853200500 ],
+ "verificationCode" : "688201",
+ "verified" : true,
+ "type" : "高中"
+} ]
\ No newline at end of file
diff --git a/pom.xml b/pom.xml
new file mode 100644
index 0000000..6f1c887
--- /dev/null
+++ b/pom.xml
@@ -0,0 +1,50 @@
+
+
+ 4.0.0
+
+ com.mathlearning
+ math-learning-app
+ 1.0.0
+
+
+ 11
+ 11
+ UTF-8
+
+
+
+
+
+ com.sun.mail
+ javax.mail
+ 1.6.2
+
+
+
+
+ com.fasterxml.jackson.core
+ jackson-core
+ 2.15.2
+
+
+ com.fasterxml.jackson.core
+ jackson-databind
+ 2.15.2
+
+
+ com.fasterxml.jackson.datatype
+ jackson-datatype-jsr310
+ 2.15.2
+
+
+
+
+ at.favre.lib
+ bcrypt
+ 0.9.0
+
+
+
\ No newline at end of file
diff --git a/src/main/java/mathlearning/model/User.java b/src/main/java/mathlearning/model/User.java
index 6ee96a3..cbf61cd 100644
--- a/src/main/java/mathlearning/model/User.java
+++ b/src/main/java/mathlearning/model/User.java
@@ -13,7 +13,7 @@ public class User {
private boolean verified;
private String type;
- public User() {}
+ public User( ) {}
public User(String email, String passwordHash, String verificationCode) {
this.email = email;
diff --git a/src/main/java/mathlearning/service/MultipleChoiceGenerator/MultipleChoiceGenerator.java b/src/main/java/mathlearning/service/MultipleChoiceGenerator/MultipleChoiceGenerator.java
index 3a7ba1a..f844f1a 100644
--- a/src/main/java/mathlearning/service/MultipleChoiceGenerator/MultipleChoiceGenerator.java
+++ b/src/main/java/mathlearning/service/MultipleChoiceGenerator/MultipleChoiceGenerator.java
@@ -14,7 +14,7 @@ public class MultipleChoiceGenerator {
public MultipleChoiceGenerator(int count, User nowUser){// 如此声明MultipleChoiceGenerator实例,再调用下面三个接口
this.QuestionList = new String[count];
this.ChoiceList = new String[count];
- this.CorrectAnswerNo = new String[count];
+ this.CorrectAnswerNo = new String[count];
this.QuestionList = SetQuestionList(count, nowUser);
SetChoiceList();
}
@@ -98,4 +98,4 @@ public class MultipleChoiceGenerator {
-}
+}
\ 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 f9c0c95..930e3b1 100644
--- a/src/main/java/mathlearning/service/UserService.java
+++ b/src/main/java/mathlearning/service/UserService.java
@@ -123,28 +123,32 @@ public class UserService {
return result.verified;
}
- public boolean changePassword(String email, String oldPassword, String newPassword) {
+ public int changePassword(String email, String oldPassword, String newPassword) {
User user = users.get(email);
if (user == null) {
- return false;
+ return 1;
}
// 验证旧密码
BCrypt.Result result = BCrypt.verifyer().verify(oldPassword.toCharArray(), user.getPasswordHash());
if (!result.verified) {
- return false;
+ return 2;
}
// 验证新密码格式
if (!validatePassword(newPassword)) {
- return false;
+ return 3;
+ }
+
+ if (oldPassword.equals(newPassword)) {
+ return 4;
}
// 更新密码
String newPasswordHash = BCrypt.withDefaults().hashToString(12, newPassword.toCharArray());
user.setPasswordHash(newPasswordHash);
saveUsers();
- return true;
+ return 5;
}
public boolean setPasswordResetCode(String email, String verificationCode) {
@@ -226,6 +230,16 @@ public class UserService {
return user != null && user.isVerified();
}
+ public boolean updateUsername(String email, String newUsername) {
+ User user = users.get(email);
+ if (user == null) {
+ return false;
+ }
+ user.setUsername(newUsername);
+ saveUsers();
+ return true;
+ }
+
public boolean isValidEmail(String email) {
return email.matches("^[A-Za-z0-9+_.-]+@(.+)$");
}
diff --git a/src/main/java/mathlearning/ui/ChangeCodeFrame.java b/src/main/java/mathlearning/ui/ChangeCodeFrame.java
index 1255136..37ad12b 100644
--- a/src/main/java/mathlearning/ui/ChangeCodeFrame.java
+++ b/src/main/java/mathlearning/ui/ChangeCodeFrame.java
@@ -36,12 +36,19 @@ public class ChangeCodeFrame extends JFrame {
true
);
+ addWindowListener(new java.awt.event.WindowAdapter() {
+ @Override
+ public void windowClosing(java.awt.event.WindowEvent windowEvent) {
+ loginFrame.setVisible(true);
+ }
+ });
+
initializeUI();
}
private void initializeUI() {
setTitle("数学学习软件 - 忘记密码");
- setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
+ setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
setSize(450, 400);
setLocationRelativeTo(null);
setResizable(false);
diff --git a/src/main/java/mathlearning/ui/ChangePasswordFrame.java b/src/main/java/mathlearning/ui/ChangePasswordFrame.java
new file mode 100644
index 0000000..96848fe
--- /dev/null
+++ b/src/main/java/mathlearning/ui/ChangePasswordFrame.java
@@ -0,0 +1,120 @@
+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 ChangePasswordFrame extends JFrame {
+ private User user;
+ private UserService userService;
+ private ProfileFrame profileFrame;
+ private JPasswordField oldPasswordField;
+ private JPasswordField newPasswordField;
+ private JPasswordField confirmPasswordField;
+
+ public ChangePasswordFrame(User user, UserService userService, ProfileFrame profileFrame) {
+ this.user = user;
+ this.userService = userService;
+ this.profileFrame = profileFrame;
+ addWindowListener(new java.awt.event.WindowAdapter() {
+ @Override
+ public void windowClosing(java.awt.event.WindowEvent windowEvent) {
+ profileFrame.setVisible(true);
+ }
+ });
+ InitUI();
+ }
+
+ private void InitUI() {
+ setTitle("修改密码");
+ setSize(400, 300);
+ setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
+ 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 infoPanel = new JPanel(new GridLayout(4, 2, 10, 10));
+ JLabel oldPasswordLabel = new JLabel("请输入旧密码:");
+ oldPasswordLabel.setFont(new Font("微软雅黑", Font.PLAIN, 14));
+ oldPasswordField = new JPasswordField();
+ infoPanel.add(oldPasswordLabel);
+ infoPanel.add(oldPasswordField);
+ JLabel newPasswordLabel = new JLabel("请输入新密码:");
+ newPasswordLabel.setFont(new Font("微软雅黑", Font.PLAIN, 14));
+ newPasswordField = new JPasswordField();
+ infoPanel.add(newPasswordLabel);
+ infoPanel.add(newPasswordField);
+ JLabel confirmPasswordLabel = new JLabel("请再次输入新密码:");
+ confirmPasswordLabel.setFont(new Font("微软雅黑", Font.PLAIN, 14));
+ confirmPasswordField = new JPasswordField();
+ infoPanel.add(confirmPasswordLabel);
+ infoPanel.add(confirmPasswordField);
+ mainPanel.add(infoPanel, BorderLayout.CENTER);
+
+ //按钮
+ JPanel buttonPanel = new JPanel(new FlowLayout());
+ JButton changeButton = new JButton("修改");
+ changeButton.addActionListener(new ChangeButtonListener());
+ JButton cancelButton = new JButton("取消并返回");
+ cancelButton.addActionListener(e -> returnToProfileFrame());
+
+ buttonPanel.add(changeButton);
+ buttonPanel.add(cancelButton);
+
+ mainPanel.add(buttonPanel, BorderLayout.SOUTH);
+
+ add(mainPanel);
+ }
+
+ private void returnToProfileFrame() {
+ profileFrame.setVisible(true);
+ dispose();
+ }
+
+ private class ChangeButtonListener implements ActionListener {
+ @Override
+ public void actionPerformed(ActionEvent e) {
+ String oldPassword = new String(oldPasswordField.getPassword());
+ String newPassword = new String(newPasswordField.getPassword());
+ String confirmPassword = new String(confirmPasswordField.getPassword());
+
+ if (!newPassword.equals(confirmPassword)) {
+ JOptionPane.showMessageDialog(ChangePasswordFrame.this, "两次输入的密码不相同!", "错误", JOptionPane.ERROR_MESSAGE );
+ return;
+ }
+
+ int changed = userService.changePassword(user.getEmail(), oldPassword, newPassword);
+
+ if (changed == 1) {
+ JOptionPane.showMessageDialog(ChangePasswordFrame.this, "修改失败!用户账户异常!", "错误", JOptionPane.ERROR_MESSAGE);
+ return;
+ }
+ else if (changed == 2) {
+ JOptionPane.showMessageDialog(ChangePasswordFrame.this, "修改失败!旧密码输入有误!", "错误", JOptionPane.ERROR_MESSAGE);
+ return;
+ } else if (changed == 3) {
+ JOptionPane.showMessageDialog(ChangePasswordFrame.this, "修改失败!新密码的格式有误!密码必须为6-10位,且包含大小写字母和数字", "错误", JOptionPane.ERROR_MESSAGE);
+ return;
+ } else if (changed == 4) {
+ JOptionPane.showMessageDialog(ChangePasswordFrame.this, "修改失败!旧密码与新密码一致!", "错误", JOptionPane.ERROR_MESSAGE);
+ return;
+ } else {
+ JOptionPane.showMessageDialog(ChangePasswordFrame.this, "修改成功!", "成功", JOptionPane.INFORMATION_MESSAGE);
+ }
+ returnToProfileFrame();
+ }
+ }
+}
diff --git a/src/main/java/mathlearning/ui/LoginFrame.java b/src/main/java/mathlearning/ui/LoginFrame.java
index b6d00b0..b2f5a96 100644
--- a/src/main/java/mathlearning/ui/LoginFrame.java
+++ b/src/main/java/mathlearning/ui/LoginFrame.java
@@ -157,6 +157,12 @@ public class LoginFrame extends JFrame{
"登录成功", JOptionPane.INFORMATION_MESSAGE);
}
- // openMainApplicationWindow(user);
+ openMainApplicationWindow(user, userService);
+ }
+
+ private void openMainApplicationWindow(User user, UserService userService) {
+ MainFrame mainFrame = new MainFrame(user, userService);
+ mainFrame.setVisible(true);
+ dispose();
}
}
diff --git a/src/main/java/mathlearning/ui/MainFrame.java b/src/main/java/mathlearning/ui/MainFrame.java
index abf8743..18b6a0f 100644
--- a/src/main/java/mathlearning/ui/MainFrame.java
+++ b/src/main/java/mathlearning/ui/MainFrame.java
@@ -1,5 +1,6 @@
package mathlearning.ui;
+import com.sun.tools.javac.Main;
import mathlearning.model.User;
import mathlearning.service.UserService;
@@ -12,6 +13,9 @@ public class MainFrame extends JFrame {
private User currentUser;
private UserService userService;
private JLabel welcomeLabel;
+ private JLabel typeLabel;
+ private JButton changeTypeButton;
+ private JPanel mainPanel;
public MainFrame(User user, UserService userService) {
this.currentUser = user;
@@ -28,14 +32,14 @@ public class MainFrame extends JFrame {
// 主面板
JPanel titlePanel = new JPanel(new BorderLayout());
- JPanel mainPanel = new JPanel(new BorderLayout(10, 10));
+ 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 = new JLabel("当前选择的测试题为" + currentUser.getType() + "难度", JLabel.CENTER);
typeLabel.setFont(new Font("微软雅黑", Font.BOLD, 16));
typeLabel.setForeground(Color.BLUE);
@@ -46,8 +50,126 @@ public class MainFrame extends JFrame {
// 功能按钮区域
JPanel centerButtonPanel = new JPanel(new GridLayout(2, 1, 15, 15));
centerButtonPanel.setBorder(BorderFactory.createEmptyBorder(30, 50, 30, 50));
+ // 切换教育阶段按钮
+ changeTypeButton = new JButton("切换教育阶段");
+ changeTypeButton.setFont(new Font("微软雅黑", Font.BOLD, 18));
+ changeTypeButton.setBackground(new Color(70, 130, 180));
+ changeTypeButton.setForeground(Color.WHITE);
+ changeTypeButton.setPreferredSize(new Dimension(200, 60));
+ changeTypeButton.addActionListener(new ChangeTypeListener());
+ // 自我测试按钮
+ JButton selfTestButton = new JButton("自我测试");
+ selfTestButton.setFont(new Font("微软雅黑", Font.BOLD, 18));
+ selfTestButton.setBackground(new Color(34, 139, 34));
+ selfTestButton.setForeground(Color.WHITE);
+ selfTestButton.setPreferredSize(new Dimension(200, 60));
+ selfTestButton.addActionListener(e -> openSelfTestFrame());
+ centerButtonPanel.add(changeTypeButton);
+ centerButtonPanel.add(selfTestButton);
+ mainPanel.add(centerButtonPanel, BorderLayout.CENTER);
+ // 底部按钮面板 - 两个较小按钮
+ JPanel bottomButtonPanel = new JPanel(new FlowLayout(FlowLayout.CENTER, 20, 10));
+
+ // 退出登录按钮
+ JButton logoutButton = new JButton("退出登录");
+ logoutButton.setFont(new Font("微软雅黑", Font.PLAIN, 14));
+ logoutButton.setBackground(Color.CYAN);
+ logoutButton.setForeground(Color.WHITE);
+ logoutButton.addActionListener(new LogoutListener());
+
+ // 个人资料按钮
+ JButton profileButton = new JButton("个人资料");
+ profileButton.setFont(new Font("微软雅黑", Font.PLAIN, 14));
+ profileButton.setBackground(new Color(100, 149, 237));
+ profileButton.setForeground(Color.WHITE);
+ profileButton.addActionListener(new ProfileListener());
+
+ bottomButtonPanel.add(logoutButton);
+ bottomButtonPanel.add(profileButton);
+ mainPanel.add(bottomButtonPanel, BorderLayout.SOUTH);
+
+ add(mainPanel);
+ }
+
+ private class ChangeTypeListener implements ActionListener {
+ @Override
+ public void actionPerformed(ActionEvent e) {
+ String[] types = {"小学", "初中", "高中" };
+ String selectedType = (String) JOptionPane.showInputDialog(MainFrame.this, "请选择需要切换的难度:", "选择难度", JOptionPane.QUESTION_MESSAGE, null, types, currentUser.getType());
+ if (selectedType != null) {
+ boolean updated = userService.updateUserType(currentUser.getEmail(), selectedType);
+
+ if (updated) {
+ currentUser.setType(selectedType);
+ JOptionPane.showMessageDialog(MainFrame.this, "当前难度已更改为" + currentUser.getType() , "切换成功", JOptionPane.INFORMATION_MESSAGE);
+ updateTypeDisplay();
+ } else {
+ JOptionPane.showMessageDialog(MainFrame.this, "切换失败", "错误", JOptionPane.ERROR_MESSAGE);
+ }
+ }
+ }
+ }
+
+ private void updateTypeDisplay() {
+ typeLabel.setText("当前选择的测试题为" + currentUser.getType() + "难度");
+ }
+
+ private class LogoutListener implements ActionListener {
+ @Override
+ public void actionPerformed(ActionEvent e) {
+ int result = JOptionPane.showConfirmDialog(MainFrame.this, "确定要退出登陆吗?", "退出登录", JOptionPane.YES_NO_OPTION);
+
+ if (result == JOptionPane.YES_OPTION) {// 为按钮添加边框和圆角效果
+ changeTypeButton.setBorder(BorderFactory.createCompoundBorder(
+ BorderFactory.createLineBorder(new Color(50, 100, 150), 1),
+ BorderFactory.createEmptyBorder(10, 20, 10, 20)));
+ changeTypeButton.setFocusPainted(false); // 去除焦点边框
+
+ // 为主面板添加渐变背景
+ mainPanel.setBackground(new Color(245, 245, 245));
+
+ LoginFrame loginFrame = new LoginFrame(userService);
+ loginFrame.setVisible(true);
+ dispose();
+ }
+ }
+ }
+
+ private class ProfileListener implements ActionListener {
+ @Override
+ public void actionPerformed(ActionEvent e) {
+ ProfileFrame profileFrame = new ProfileFrame(currentUser, userService);
+ profileFrame.setVisible(true);
+ dispose();
+ }
+ }
+
+ private void openSelfTestFrame() {
+ String input = JOptionPane.showInputDialog(MainFrame.this, "请输入题目数量:(10-30)", "题目数量", JOptionPane.QUESTION_MESSAGE);
+ if (input == null) {
+ return;
+ }
+
+ try {
+ int num = Integer.parseInt(input.trim());
+ if (num < 10 || num > 30) {
+ JOptionPane.showMessageDialog(MainFrame.this, "题目数量应该在10-30之间!", "错误", JOptionPane.ERROR_MESSAGE);
+ return;
+ }
+ SelTestFrame selTestFrame = new SelTestFrame(this, currentUser, userService, num);
+ selTestFrame.setVisible(true);
+ this.setVisible(false);
+
+ } catch (NumberFormatException e) {
+ JOptionPane.showMessageDialog(MainFrame.this, "请输入数字!", "错误", JOptionPane.ERROR_MESSAGE);
+ }
+
+ }
+
+ public void reTryTest() {
+ openSelfTestFrame();
}
}
diff --git a/src/main/java/mathlearning/ui/ProfileFrame.java b/src/main/java/mathlearning/ui/ProfileFrame.java
new file mode 100644
index 0000000..8f2b3cf
--- /dev/null
+++ b/src/main/java/mathlearning/ui/ProfileFrame.java
@@ -0,0 +1,130 @@
+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 ProfileFrame extends JFrame {
+ private User user;
+ private UserService userService;
+ private JPanel mainPanel;
+ private JLabel usernameValue;
+
+ public ProfileFrame(User user, UserService userService) {
+ this.user = user;
+ this.userService = userService;
+ addWindowListener(new java.awt.event.WindowAdapter() {
+ @Override
+ public void windowClosing(java.awt.event.WindowEvent windowEvent) {
+ MainFrame mainFrame = new MainFrame(user, userService);
+ mainFrame.setVisible(true);
+ }
+ });
+ InitUI();
+ }
+
+ private void InitUI() {
+ setTitle("个人资料");
+ setSize(400, 300);
+ setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
+ setLocationRelativeTo(null);
+ setResizable(false);
+
+ // 创建主面板
+ 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 infoPanel = new JPanel(new GridLayout(3, 2, 10, 10));
+ JLabel usernameLabel = new JLabel("用户名:");
+ usernameLabel.setFont(new Font("微软雅黑", Font.PLAIN, 14));
+ usernameValue = new JLabel(user.getUsername());
+ usernameLabel.setFont(new Font("微软雅黑", Font.PLAIN, 14));
+ infoPanel.add(usernameLabel);
+ infoPanel.add(usernameValue);
+ JLabel mailLabel = new JLabel("QQ邮箱:");
+ mailLabel.setFont(new Font("微软雅黑", Font.PLAIN, 14));
+ JLabel mailValue = new JLabel(user.getEmail());
+ infoPanel.add(mailLabel);
+ infoPanel.add(mailValue);
+ mainPanel.add(infoPanel, BorderLayout.CENTER);
+
+ //三个按钮
+ JPanel buttonPanel = new JPanel(new FlowLayout());
+ JButton returnToMainButton = new JButton("返回");
+ returnToMainButton.addActionListener(new returnToMainButtonListener());
+
+ JButton changePasswordButton = new JButton("修改密码");
+ changePasswordButton.addActionListener(e -> openChangePasswordFrame());
+
+ JButton changeUsernameButton = new JButton("更改用户名");
+ changeUsernameButton.addActionListener(new ChangeUsernameButtonListener());
+
+ buttonPanel.add(returnToMainButton);
+ buttonPanel.add(changePasswordButton);
+ buttonPanel.add(changeUsernameButton);
+
+ mainPanel.add(buttonPanel, BorderLayout.SOUTH);
+
+ add(mainPanel);
+ }
+
+ private class returnToMainButtonListener implements ActionListener {
+ @Override
+ public void actionPerformed(ActionEvent e) {
+ MainFrame mainFrame = new MainFrame(user, userService);
+ mainFrame.setVisible(true);
+ dispose();
+ }
+ }
+
+ private void openChangePasswordFrame() {
+ ChangePasswordFrame changePasswordFrame = new ChangePasswordFrame(user, userService, this);
+ changePasswordFrame.setVisible(true);
+ this.setVisible(false);
+ }
+
+ private class ChangeUsernameButtonListener implements ActionListener {
+ @Override
+ public void actionPerformed(ActionEvent e ) {
+ String newUsername = JOptionPane.showInputDialog(ProfileFrame.this, "请输入您的新用户名:", "修改用户名", JOptionPane.QUESTION_MESSAGE);
+
+ if (newUsername == null ) {
+ return;
+ }
+
+ newUsername = newUsername.trim();
+ if (newUsername.isEmpty()) {
+ JOptionPane.showMessageDialog( ProfileFrame.this, "用户名不能为空!", "错误", JOptionPane.ERROR_MESSAGE);
+ return;
+ }
+ if (newUsername.equals(user.getUsername())) {
+ JOptionPane.showMessageDialog( ProfileFrame.this, "新用户名与原用户名相同!", "提示", JOptionPane.ERROR_MESSAGE);
+ return;
+ }
+ int confirm = JOptionPane.showConfirmDialog(ProfileFrame.this,"确定要修改用户名为\"" + newUsername + "\"吗?", "修改用户名", JOptionPane.YES_NO_OPTION);
+ if (confirm == JOptionPane.YES_OPTION) {
+ String oldUsername = user.getUsername();
+
+ boolean updated = userService.updateUsername(user.getEmail(), newUsername);
+ if (updated) {
+ usernameValue.setText(newUsername);
+ JOptionPane.showMessageDialog(ProfileFrame.this, "修改成功!", "成功", JOptionPane.INFORMATION_MESSAGE);
+ }
+ else {
+ user.setUsername(oldUsername);
+ JOptionPane.showMessageDialog(ProfileFrame.this, "修改失败!", "错误", JOptionPane.ERROR_MESSAGE);
+ }
+ }
+ }
+ }
+}
diff --git a/src/main/java/mathlearning/ui/RegisterFrame.java b/src/main/java/mathlearning/ui/RegisterFrame.java
index b5fc993..fb0f5a9 100644
--- a/src/main/java/mathlearning/ui/RegisterFrame.java
+++ b/src/main/java/mathlearning/ui/RegisterFrame.java
@@ -37,12 +37,19 @@ public class RegisterFrame extends JFrame{
true
);
+ addWindowListener(new java.awt.event.WindowAdapter() {
+ @Override
+ public void windowClosing(java.awt.event.WindowEvent windowEvent) {
+ loginFrame.setVisible(true);
+ }
+ });
+
initializeUI();
}
private void initializeUI() {
setTitle("数学学习软件 - 注册");
- setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
+ setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
setSize(450, 400);
setLocationRelativeTo(null);
setResizable(false);
diff --git a/src/main/java/mathlearning/ui/SelTestFrame.java b/src/main/java/mathlearning/ui/SelTestFrame.java
new file mode 100644
index 0000000..327e3d7
--- /dev/null
+++ b/src/main/java/mathlearning/ui/SelTestFrame.java
@@ -0,0 +1,324 @@
+package mathlearning.ui;
+
+import mathlearning.model.User;
+import mathlearning.service.MultipleChoiceGenerator.MultipleChoiceGenerator;
+import mathlearning.service.UserService;
+
+import javax.swing.*;
+import java.awt.*;
+
+public class SelTestFrame extends JFrame {
+ private MainFrame mainFrame;
+ private User user;
+ private UserService userService;
+ private MultipleChoiceGenerator multipleChoiceGenerator;
+
+ private int questionNum;
+ private int currentQuestionDex;
+ private String[] answers;
+ private String[] myAnswers;
+
+ private JLabel titleLabel;
+ private JButton optionA;
+ private JButton optionB;
+ private JButton optionC;
+ private JButton optionD;
+ private JButton prevButton;
+ private JButton nextButton;
+ private JButton submitButton;
+ private JLabel question;
+ private JLabel choice;
+
+ public SelTestFrame(MainFrame mainFrame, User user, UserService userService, int num) {
+ this.mainFrame = mainFrame;
+ this.user = user;
+ this.userService = userService;
+ this.questionNum = num;
+ this.currentQuestionDex = 0;
+ this.myAnswers = new String[questionNum];
+ this.multipleChoiceGenerator = new MultipleChoiceGenerator(num, user);
+ this.answers = multipleChoiceGenerator.GetCorrectAnswerNo();
+ InitUI();
+ addWindowListener(new java.awt.event.WindowAdapter() {
+ @Override
+ public void windowClosing(java.awt.event.WindowEvent windowEvent) {
+ handleCloseOperation();
+ }
+ });
+ }
+
+ private void InitUI() {
+ setTitle("答题界面");
+ setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
+ setSize(800, 600);
+ setLocationRelativeTo(null);
+
+ //主面板
+ JPanel mainPanel = new JPanel(new BorderLayout());
+
+ //上
+ titleLabel = new JLabel("当前为:第" + (currentQuestionDex + 1) + "题");
+
+ //左侧面板
+ JPanel leftPanel = createLeftPanel();
+
+ //中
+ JPanel centerPanel = centerPanel();
+
+ //右
+ JPanel rightPanel = createRightPanel();
+
+ //底
+ JPanel bottomPanel = createButtonPanel();
+
+ mainPanel.add(titleLabel, BorderLayout.NORTH);
+ mainPanel.add(leftPanel, BorderLayout.WEST);
+ mainPanel.add(centerPanel, BorderLayout.CENTER);
+ mainPanel.add(rightPanel, BorderLayout.EAST);
+ mainPanel.add(bottomPanel, BorderLayout.SOUTH);
+
+ add(mainPanel);
+
+ updateNavigationButtons();
+ }
+
+ private JPanel createLeftPanel() {
+ JPanel panel = new JPanel(new BorderLayout());
+
+ JLabel usernameLabel = new JLabel("用户:" + user.getUsername());
+ usernameLabel.setFont(new Font("微软雅黑", Font.BOLD, 16));
+ usernameLabel.setForeground(Color.BLUE);
+ panel.add(usernameLabel, BorderLayout.NORTH);
+
+ JList questionList = new JList<>();
+ String[] questions = new String[questionNum + 1];
+ for (int i = 0; i < questionNum; i++) {
+ questions[i] = "题目" + (i + 1);
+ }
+ questionList.setListData(questions);
+ panel.add(questionList, BorderLayout.CENTER);
+
+ return panel;
+ }
+
+ private JPanel centerPanel() {
+ JPanel panel = new JPanel(new GridLayout(6, 1));
+
+ JLabel questionLabel = new JLabel("题目:");
+ questionLabel.setFont(new Font("微软雅黑", Font.PLAIN, 14));
+ question = new JLabel(multipleChoiceGenerator.GetQuestionList()[currentQuestionDex]);
+ question.setFont(new Font("微软雅黑", Font.PLAIN, 14));
+ panel.add(questionLabel);
+ panel.add(question);
+
+ JLabel choiceLabel = new JLabel("选项:");
+ choiceLabel.setFont(new Font("微软雅黑", Font.PLAIN, 14));
+ choice = new JLabel(multipleChoiceGenerator.GetChoiceList()[currentQuestionDex]);
+ choiceLabel.setFont(new Font("微软雅黑", Font.PLAIN, 16));
+ panel.add(choiceLabel);
+ panel.add(choice);
+
+ return panel;
+ }
+
+ private JPanel createRightPanel() {
+ JPanel panel = new JPanel(new BorderLayout());
+
+ JLabel titleLabel = new JLabel("作答区域:");
+ titleLabel.setFont(new Font("微软雅黑", Font.BOLD, 16));
+ panel.add(titleLabel, BorderLayout.NORTH);
+
+ JPanel buttonPanel = new JPanel(new GridLayout(4, 1));
+
+ optionA = new JButton("A");
+ optionA.setBackground(Color.LIGHT_GRAY);
+ optionA.setForeground(Color.BLACK);
+ optionA.addActionListener(e -> saveAnswer("A"));
+ optionB = new JButton("B");
+ optionB.setBackground(Color.LIGHT_GRAY);
+ optionB.setForeground(Color.BLACK);
+ optionB.addActionListener(e -> saveAnswer("B"));
+ optionC = new JButton("C");
+ optionC.setBackground(Color.LIGHT_GRAY);
+ optionC.setForeground(Color.BLACK);
+ optionC.addActionListener(e -> saveAnswer("C"));
+ optionD = new JButton("D");
+ optionD.setBackground(Color.LIGHT_GRAY);
+ optionD.setForeground(Color.BLACK);
+ optionD.addActionListener(e -> saveAnswer("D"));
+ buttonPanel.add(optionA);
+ buttonPanel.add(optionB);
+ buttonPanel.add(optionC);
+ buttonPanel.add(optionD);
+ panel.add(buttonPanel, BorderLayout.CENTER);
+
+ return panel;
+ }
+
+ private JPanel createButtonPanel() {
+ JPanel panel = new JPanel(new FlowLayout());
+
+ prevButton = new JButton("上一题");
+ prevButton.addActionListener(e -> goToPrevQuestion());
+
+ nextButton = new JButton("下一题");
+ nextButton.addActionListener(e -> goToNextQuestion());
+
+ submitButton = new JButton("提交");
+ submitButton.addActionListener(e -> goToSubmit());
+
+ panel.add(prevButton);
+ panel.add(nextButton);
+ panel.add(submitButton);
+ return panel;
+ }
+
+ private void saveAnswer(String answer) {
+ resetButtonColors();
+
+ switch (answer) {
+ case "A":
+ optionA.setBackground(Color.GREEN);
+ myAnswers[currentQuestionDex] = answer;
+ break;
+ case "B":
+ optionB.setBackground(Color.GREEN);
+ myAnswers[currentQuestionDex] = answer;
+ break;
+ case "C":
+ optionC.setBackground(Color.GREEN);
+ myAnswers[currentQuestionDex] = answer;
+ break;
+ case "D":
+ optionD.setBackground(Color.GREEN);
+ myAnswers[currentQuestionDex] = answer;
+ break;
+ }
+
+ }
+
+ private void resetButtonColors() {
+ optionA.setBackground(Color.LIGHT_GRAY);
+ optionB.setBackground(Color.LIGHT_GRAY);
+ optionC.setBackground(Color.LIGHT_GRAY);
+ optionD.setBackground(Color.LIGHT_GRAY);
+ }
+
+ private void goToPrevQuestion() {
+ if (currentQuestionDex > 0) {
+ currentQuestionDex--;
+ updateTitleLabel();
+ updateQuestion();
+ if (myAnswers[currentQuestionDex] == null) {
+ resetButtonColors();
+ }
+ else {
+ saveAnswer(myAnswers[currentQuestionDex]);
+ }
+
+ updateNavigationButtons();
+ }
+ }
+
+ private void goToNextQuestion() {
+ if (currentQuestionDex < questionNum - 1) {
+ currentQuestionDex++;
+ updateTitleLabel();
+ updateQuestion();
+ if (myAnswers[currentQuestionDex] == null) {
+ resetButtonColors();
+ } else {
+ saveAnswer(myAnswers[currentQuestionDex]);
+ }
+
+ updateNavigationButtons();
+ }
+ }
+
+ private void goToSubmit() {
+ int confirm = JOptionPane.showConfirmDialog(SelTestFrame.this, "你确定要提交试卷吗?", "提示", JOptionPane.YES_NO_OPTION);
+ if (confirm == JOptionPane.YES_OPTION) {
+ int correctCount = 0;
+ correctCount = getScore(answers, myAnswers);
+
+ double accuracy = Math.round((double) correctCount / myAnswers.length * 10000) / 100.0;
+ double score = Math.round((double) correctCount * 100 / myAnswers.length * 10) / 10.0;
+
+ // 弹出分数结果
+ String[] options = {"返回主菜单", "继续做题"};
+ int choice = JOptionPane.showOptionDialog(
+ SelTestFrame.this,
+ "您答对了" + correctCount + "道题,正确率为" + String.format("%.2f", accuracy) + "\n您的得分是: " + score + "分",
+ "测试结果",
+ JOptionPane.YES_NO_OPTION,
+ JOptionPane.INFORMATION_MESSAGE,
+ null,
+ options,
+ options[0]
+ );
+
+ if (choice == 0) {
+ mainFrame.setVisible(true);
+ dispose();
+ } else if (choice == 1) {
+ dispose();
+ mainFrame.setVisible(true);
+ mainFrame.reTryTest();
+ }
+ }
+ }
+
+ private void updateNavigationButtons() {
+ if (currentQuestionDex == 0) {
+ prevButton.setEnabled(false);
+ prevButton.setVisible(false);
+ }
+ else {
+ prevButton.setEnabled(true);
+ prevButton.setVisible(true);
+ }
+
+ if (currentQuestionDex == questionNum - 1) {
+ nextButton.setEnabled(false);
+ nextButton.setVisible(false);
+ submitButton.setEnabled(true);
+ submitButton.setVisible(true);
+ } else {
+ nextButton.setEnabled(true);
+ nextButton.setVisible(true);
+ submitButton.setEnabled(false);
+ submitButton.setVisible(false);
+ }
+ }
+
+ private void updateTitleLabel() {
+ titleLabel.setText("当前为:第" + (currentQuestionDex + 1) + "题");
+ }
+
+ private void handleCloseOperation() {
+ int result = JOptionPane.showConfirmDialog(SelTestFrame.this, "确定要中途退出答题吗?当前答题进度将会丢失!", "确认退出", JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE);
+
+ if (result == JOptionPane.YES_OPTION) {
+ mainFrame.setVisible(true);
+ dispose();
+ }
+ }
+
+ private int getScore(String[] answers, String[] myAnswers) {
+ if (answers == null || myAnswers == null){
+ return 0;
+ }
+ int score = 0;
+ for (int i = 0; i < answers.length; i++) {
+ if (answers[i] != null && answers[i].equals(myAnswers[i])){
+ score++;
+ }
+ }
+ return score;
+ }
+
+ private void updateQuestion() {
+ question.setText(multipleChoiceGenerator.GetQuestionList()[currentQuestionDex]);
+ choice.setText(multipleChoiceGenerator.GetChoiceList()[currentQuestionDex]);
+ }
+}