From 1e223f1c54558213012f98bfc187b7795a80ce16 Mon Sep 17 00:00:00 2001 From: Arno <15528622+arno-1@user.noreply.gitee.com> Date: Thu, 9 Oct 2025 16:21:56 +0800 Subject: [PATCH] Fourth commit --- doc/README.md | 58 ++++++++++ src/Base/Email_settings.java | 91 ++++++++++++++-- src/Generator/Generate_paper.java | 53 +++++++++ src/META-INF/MANIFEST.MF | 3 + src/Math_learning_app.java | 22 ++++ src/Send_Email/Send_email.java | 12 +-- src/Service/Exam_service.java | 3 +- src/View/Exam_frame.java | 173 ++++++++++++++++++++++++++++++ src/View/Login_frame.java | 104 ++++++++++++++++++ src/View/Main_frame.java | 156 +++++++++++++++++++++++++++ src/View/Register_frame.java | 167 ++++++++++++++++++++++++++++ src/View/Result_frame.java | 82 ++++++++++++++ src/View/Review_frame.java | 148 +++++++++++++++++++++++++ 13 files changed, 1056 insertions(+), 16 deletions(-) create mode 100644 doc/README.md create mode 100644 src/Generator/Generate_paper.java create mode 100644 src/META-INF/MANIFEST.MF create mode 100644 src/Math_learning_app.java create mode 100644 src/View/Exam_frame.java create mode 100644 src/View/Login_frame.java create mode 100644 src/View/Main_frame.java create mode 100644 src/View/Register_frame.java create mode 100644 src/View/Result_frame.java create mode 100644 src/View/Review_frame.java diff --git a/doc/README.md b/doc/README.md new file mode 100644 index 0000000..8e05793 --- /dev/null +++ b/doc/README.md @@ -0,0 +1,58 @@ +# 带UI的数学学习软件 + +## 项目结构 +Math_learning +|——lib  依赖(jar包) +  |——javax.mail-1.6.2.jar  发送邮件相关 +  |——activation-1.1.1.jar  javax.mail所需依赖 +|——src  源代码目录 +  |——Base  基础类包 +    |——Email_settings.java  邮件发送服务配置 +    |——Exam_result.java  考试结果类 +    |——Question.java  题目类 +    |——User.java  用户类 +  |——Generator  题目生成器包 +    |——G_ques.java  生成器接口 +    |——Pri_g_ques.java  小学题目生成器 +    |——Jun_g_ques.java  初中题目生成器 +    |——Sen_g_ques.java  高中题目生成器 +    |——Generate_paper.java  生成试卷 +  |——Send_Email  邮件发送包 +    |——Deal_i_code.java  管理验证码以及验证码校验 +    |——Generate_i_code.java  产生验证码 +    |——Send_email.java  发送邮件类 +  |——Service  服务类包,供前端调用 +    |——User_service.java  用户服务类,包括注册、登录、修改密码等 +    |——Exam_service.java  考试服务类 +    |——Deal_file.java  可选功能:保存试卷为文件 +  |——View  前端类包 + +|——doc  说明文档 +  |——README.md + +## 邮件发送说明 +  发件人信息通过配置文件存储,首次运行时会创建config/email.properties配置文件,并使用默认配置(乔毅凡的qq邮箱) +  修改配置文件可更改发件人配置,如果要使用自己的邮箱,需要去设置中开启特定配置。 +以QQ邮箱为例子: +1. 需要去自己的邮箱设置中找到POP3/IMAP/SMTP/Exchange/CardDAV 服务,选择开启,生成授权码。 +2. 查看QQ邮箱配置方法中的说明,看到“发送邮件服务器: smtp.qq.com,使用SSL,端口号465或587”,这就是发件服务器和使用的端口,以及使用SSL。 +3. 将上述信息修改到配置文件中。(发件服务器、端口、SSL在默认配置中已经为QQ邮箱的配置,修改邮箱和授权码即可) +4. 其他邮箱配置方法具体见官方说明。 + +## 用户信息 +用户信息保存在本地,用户/用户信息.txt(运行时会产生) + +## 运行环境 +可执行文件:Math_Learning.jar(依赖已经打包) +Windows  UTF-8编码   + +--- +软件2302 +刘星宇 202326010226 +毛承上 202326010227 +乔毅凡 202326010228 + + + + + diff --git a/src/Base/Email_settings.java b/src/Base/Email_settings.java index 43e8fb1..ea57b1f 100644 --- a/src/Base/Email_settings.java +++ b/src/Base/Email_settings.java @@ -1,13 +1,86 @@ package Base; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.util.Properties; + public class Email_settings { - public static final String SMTP_HOST = "smtp.qq.com"; - // 邮箱服务器端口 - public static final String SMTP_PORT = "587"; - // 发件人邮箱 - public static final String FROM_EMAIL = "835981889@qq.com"; - // 发件人邮箱授权码 - public static final String EMAIL_PASSWORD = "fpqfprqznbvdbcdf"; - // 是否启用SSL - public static final boolean SSL_ENABLE = true; + private static final String CONFIG_FILE = "config/email.properties"; + private static Properties properties; + private static long lastModified = 0; + + static { + loadConfig(); + } + + private static void loadConfig() { + properties = new Properties(); + setDefaultProperties(); + File configFile = new File(CONFIG_FILE); + if (configFile.exists()) { + try (FileInputStream input = new FileInputStream(configFile)) { + properties.load(input); + lastModified = configFile.lastModified(); + } catch (IOException e) { + System.err.println("加载邮箱配置文件失败,使用默认配置: " + e.getMessage()); + } + } else { + createDefaultConfigFile(); + } + } + + private static void setDefaultProperties() { + properties.setProperty("smtp.host", "smtp.qq.com"); + properties.setProperty("smtp.port", "587"); + properties.setProperty("from.email", "835981889@qq.com"); + properties.setProperty("email.password", "fpqfprqznbvdbcdf"); + properties.setProperty("ssl.enable", "true"); + } + + private static void createDefaultConfigFile() { + File configDir = new File("config"); + if (!configDir.exists()) { + configDir.mkdirs(); + } + + try (FileOutputStream output = new FileOutputStream(CONFIG_FILE)) { + properties.store(output, "Settings"); + } catch (IOException e) { + System.err.println("创建默认配置文件失败: " + e.getMessage()); + } + } + + private static void checkForUpdates() { + File configFile = new File(CONFIG_FILE); + if (configFile.exists() && configFile.lastModified() > lastModified) { + loadConfig(); + } + } + + public static String getSmtpHost() { + checkForUpdates(); + return properties.getProperty("smtp.host"); + } + + public static String getSmtpPort() { + checkForUpdates(); + return properties.getProperty("smtp.port"); + } + + public static String getFromEmail() { + checkForUpdates(); + return properties.getProperty("from.email"); + } + + public static String getEmailPassword() { + checkForUpdates(); + return properties.getProperty("email.password"); + } + + public static boolean isSslEnable() { + checkForUpdates(); + return Boolean.parseBoolean(properties.getProperty("ssl.enable")); + } } diff --git a/src/Generator/Generate_paper.java b/src/Generator/Generate_paper.java new file mode 100644 index 0000000..ebf5c6d --- /dev/null +++ b/src/Generator/Generate_paper.java @@ -0,0 +1,53 @@ +package Generator; + +import Base.Question; +import Service.Deal_file; + +import java.util.ArrayList; + +public class Generate_paper { + public static ArrayList g_paper(int num,String type,String id) { + ArrayList result = new ArrayList<>(); + G_ques generator; + switch (type){ + case "小学":{ + generator=new Pri_g_ques(); + break; + } + case "初中":{ + generator=new Jun_g_ques(); + break; + } + case "高中":{ + generator=new Sen_g_ques(); + break; + } + default:{ + generator=new Pri_g_ques(); + } + } + for (int i=0;i all,String ques){ + for (Question q:all){ + if (q.getContent().equals(ques)){ + return true; + } + } + return false; + } +} diff --git a/src/META-INF/MANIFEST.MF b/src/META-INF/MANIFEST.MF new file mode 100644 index 0000000..f319cb5 --- /dev/null +++ b/src/META-INF/MANIFEST.MF @@ -0,0 +1,3 @@ +Manifest-Version: 1.0 +Main-Class: Math_learning_app + diff --git a/src/Math_learning_app.java b/src/Math_learning_app.java new file mode 100644 index 0000000..3292c33 --- /dev/null +++ b/src/Math_learning_app.java @@ -0,0 +1,22 @@ +import Service.User_service; +import View.Login_frame; + +import javax.swing.*; + +public class Math_learning_app { + private static User_service userService; + + public static void main(String[] args) { + initializeServices(); + SwingUtilities.invokeLater(Math_learning_app::showLoginFrame); + } + + private static void initializeServices() { + userService = new User_service(); + } + + public static void showLoginFrame() { + Login_frame loginFrame = new Login_frame(userService); + loginFrame.setVisible(true); + } +} diff --git a/src/Send_Email/Send_email.java b/src/Send_Email/Send_email.java index 5c63db7..809024f 100644 --- a/src/Send_Email/Send_email.java +++ b/src/Send_Email/Send_email.java @@ -59,23 +59,23 @@ public class Send_email { public static boolean send_email(String toEmail, String Code) { try { Properties props = new Properties(); - props.put("mail.smtp.host", Email_settings.SMTP_HOST); - props.put("mail.smtp.port", Email_settings.SMTP_PORT); + props.put("mail.smtp.host", Email_settings.getSmtpHost()); + props.put("mail.smtp.port", Email_settings.getSmtpPort()); props.put("mail.smtp.auth", "true"); - if (Email_settings.SSL_ENABLE) { + if (Email_settings.isSslEnable()) { props.put("mail.smtp.starttls.enable", "true"); - props.put("mail.smtp.ssl.trust", Email_settings.SMTP_HOST); + props.put("mail.smtp.ssl.trust", Email_settings.getSmtpHost()); } // 创建会话 Session session = Session.getInstance(props, new Authenticator() { @Override protected PasswordAuthentication getPasswordAuthentication() { - return new PasswordAuthentication(Email_settings.FROM_EMAIL, Email_settings.EMAIL_PASSWORD); + return new PasswordAuthentication(Email_settings.getFromEmail(), Email_settings.getEmailPassword()); } }); // 创建邮件消息 Message message = new MimeMessage(session); - message.setFrom(new InternetAddress(Email_settings.FROM_EMAIL)); + message.setFrom(new InternetAddress(Email_settings.getFromEmail())); message.setRecipients(Message.RecipientType.TO, InternetAddress.parse(toEmail)); message.setSubject("注册验证码"); // 邮件内容 diff --git a/src/Service/Exam_service.java b/src/Service/Exam_service.java index 30b47da..dc84cf2 100644 --- a/src/Service/Exam_service.java +++ b/src/Service/Exam_service.java @@ -2,6 +2,7 @@ package Service; import Base.Exam_result; import Base.Question; +import Generator.Generate_paper; import java.util.*; @@ -17,7 +18,7 @@ public class Exam_service { public Exam_service(int num,String type,String id){ this.id=id; this.type=type; - paper=Generate_paper.g_paper(num,type,id); + paper= Generate_paper.g_paper(num,type,id); now_index=0; this.start_time = new Date(); this.user_answers = new HashMap<>(); diff --git a/src/View/Exam_frame.java b/src/View/Exam_frame.java new file mode 100644 index 0000000..3225bc3 --- /dev/null +++ b/src/View/Exam_frame.java @@ -0,0 +1,173 @@ +package View; + +import Base.Exam_result; +import Base.Question; +import Service.Deal_file; +import Service.Exam_service; +import Service.User_service; + +import javax.swing.*; +import java.awt.*; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; + +public class Exam_frame extends JFrame { + private Exam_service examService; + private User_service userService; + private String email; + private JLabel questionLabel; + private JRadioButton[] optionButtons; + private ButtonGroup buttonGroup; + private JLabel progressLabel; + private JButton previousButton; + private JButton nextButton; + + public Exam_frame(Exam_service examService, User_service userService, String email) { + this.examService = examService; + this.userService = userService; + this.email = email; + initializeUI(); + showQuestion(); + } + + private void initializeUI() { + setTitle("考试"); + setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + setSize(600, 400); + setLocationRelativeTo(null); + setResizable(false); + + // 主面板 + JPanel mainPanel = new JPanel(new BorderLayout(10, 10)); + mainPanel.setBorder(BorderFactory.createEmptyBorder(20, 20, 20, 20)); + + // 进度标签 + progressLabel = new JLabel(); + updateProgress(); + mainPanel.add(progressLabel, BorderLayout.NORTH); + + // 题目面板 + JPanel questionPanel = new JPanel(new BorderLayout()); + questionLabel = new JLabel(); + questionLabel.setFont(new Font("微软雅黑", Font.PLAIN, 16)); + questionPanel.add(questionLabel, BorderLayout.NORTH); + + // 选项面板 + JPanel optionsPanel = new JPanel(new GridLayout(4, 1, 10, 10)); + optionButtons = new JRadioButton[4]; + buttonGroup = new ButtonGroup(); + for (int i = 0; i < 4; i++) { + optionButtons[i] = new JRadioButton(); + optionButtons[i].setFont(new Font("微软雅黑", Font.PLAIN, 14)); + buttonGroup.add(optionButtons[i]); + optionsPanel.add(optionButtons[i]); + } + + questionPanel.add(optionsPanel, BorderLayout.CENTER); + mainPanel.add(questionPanel, BorderLayout.CENTER); + + // 按钮面板 + JPanel buttonPanel = new JPanel(new FlowLayout()); + previousButton = new JButton("上一题"); + nextButton = new JButton("下一题"); + + buttonPanel.add(previousButton); + buttonPanel.add(nextButton); + + mainPanel.add(buttonPanel, BorderLayout.SOUTH); + + // 添加事件监听器 + previousButton.addActionListener(new PreviousListener()); + nextButton.addActionListener(new NextListener()); + + add(mainPanel); + } + + private void showQuestion() { + Question currentQuestion = examService.get_now_question(); + if (currentQuestion == null) { + return; + } + + questionLabel.setText(currentQuestion.getContent()); + for (int i = 0; i < 4; i++) { + String options = currentQuestion.getOptions(i); + optionButtons[i].setText(options); + } + + // 检查是否已经回答过该题 + Integer userAnswer = examService.get_user_answer(examService.get_now_index()); + if (userAnswer != null && userAnswer!=-1) { + optionButtons[userAnswer].setSelected(true); + } else { + buttonGroup.clearSelection(); + } + updateProgress(); + updateButtons(); + } + + private void updateProgress() { + int current = examService.get_now_index() + 1; + int total = examService.get_paper().size(); + progressLabel.setText("进度: " + current + "/" + total); + } + + private void updateButtons() { + int currentIndex = examService.get_now_index(); + int total = examService.get_paper().size(); + + previousButton.setEnabled(currentIndex > 0); + nextButton.setText(currentIndex < total - 1 ? "下一题" : "提交"); + } + + private class PreviousListener implements ActionListener { + @Override + public void actionPerformed(ActionEvent e) { + // 保存当前答案 + saveAnswer(); + if (examService.pre_one()) { + showQuestion(); + } + } + } + + private class NextListener implements ActionListener { + @Override + public void actionPerformed(ActionEvent e) { + boolean hasNext = examService.next_one(getSelectedOption()); + if (hasNext) { + showQuestion(); + } else { + if (!examService.check_finished()){ + JOptionPane.showMessageDialog(Exam_frame.this, + "有题目未完成", "错误", JOptionPane.ERROR_MESSAGE); + return; + } + Exam_result result = examService.calculate_result(); + openResultFrame(result); + } + } + } + + private void saveAnswer() { + int selected = getSelectedOption(); + if (selected != -1) { + examService.change_answer(examService.get_now_index(), selected); + } + } + + private int getSelectedOption() { + for (int i = 0; i < 4; i++) { + if (optionButtons[i].isSelected()) { + return i; + } + } + return -1; + } + + private void openResultFrame(Exam_result result) { + Result_frame resultFrame = new Result_frame(examService, result , userService, email); + resultFrame.setVisible(true); + this.dispose(); + } +} diff --git a/src/View/Login_frame.java b/src/View/Login_frame.java new file mode 100644 index 0000000..08f9e52 --- /dev/null +++ b/src/View/Login_frame.java @@ -0,0 +1,104 @@ +package View; + +import Service.User_service; + +import javax.swing.*; +import java.awt.*; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; + +public class Login_frame extends JFrame { + private User_service userService; + private JTextField idField; + private JPasswordField passwordField; + + public Login_frame(User_service userService) { + this.userService = userService; + initializeUI(); + } + + private void initializeUI() { + setTitle("登录"); + setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + setSize(400, 350); + 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(3, 2, 10, 10)); + + formPanel.add(new JLabel("用户名:")); + idField = new JTextField(); + formPanel.add(idField); + + formPanel.add(new JLabel("密码:")); + passwordField = new JPasswordField(); + formPanel.add(passwordField); + + // 按钮面板 + JPanel buttonPanel = new JPanel(new FlowLayout()); + JButton loginButton = new JButton("登录"); + JButton registerButton = new JButton("注册账号"); + JButton exitButton = new JButton("退出"); + + buttonPanel.add(loginButton); + buttonPanel.add(registerButton); + buttonPanel.add(exitButton); + + formPanel.add(buttonPanel); + + mainPanel.add(formPanel, BorderLayout.CENTER); + + // 添加事件监听器 + loginButton.addActionListener(new LoginListener()); + registerButton.addActionListener(e -> openRegisterFrame()); + exitButton.addActionListener(e -> System.exit(0)); + + add(mainPanel); + } + + private class LoginListener implements ActionListener { + @Override + public void actionPerformed(ActionEvent e) { + String id = idField.getText().trim(); + String password = new String(passwordField.getPassword()); + + if (id.isEmpty() || password.isEmpty()) { + JOptionPane.showMessageDialog(Login_frame.this, + "请输入用户名和密码", "错误", JOptionPane.ERROR_MESSAGE); + return; + } + + String result = userService.login(id, password); + if (result.equals("登陆成功")) { + JOptionPane.showMessageDialog(Login_frame.this, + "登录成功!", "成功", JOptionPane.INFORMATION_MESSAGE); + openMainFrame(userService.find_user_i(id).get_email()); + } else { + JOptionPane.showMessageDialog(Login_frame.this, + result, "登录失败", JOptionPane.ERROR_MESSAGE); + } + } + } + + private void openRegisterFrame() { + Register_frame registerFrame = new Register_frame(userService); + registerFrame.setVisible(true); + this.dispose(); + } + + private void openMainFrame(String email) { + Main_frame mainFrame = new Main_frame(userService, email); + mainFrame.setVisible(true); + this.dispose(); + } +} \ No newline at end of file diff --git a/src/View/Main_frame.java b/src/View/Main_frame.java new file mode 100644 index 0000000..b2d9c3e --- /dev/null +++ b/src/View/Main_frame.java @@ -0,0 +1,156 @@ +package View; + +import Service.Exam_service; +import Service.User_service; + +import javax.swing.*; +import java.awt.*; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; + +public class Main_frame extends JFrame { + private User_service userService; + private String email; + private JComboBox typeComboBox; + private JTextField countField; + + public Main_frame(User_service userService, String email) { + this.userService = userService; + this.email = email; + initializeUI(); + } + + private void initializeUI() { + setTitle("主界面"); + setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + setSize(500, 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 settingPanel = new JPanel(new GridLayout(2, 2, 10, 10)); + + settingPanel.add(new JLabel("选择难度:")); + typeComboBox = new JComboBox<>(new String[]{"小学", "初中", "高中"}); + settingPanel.add(typeComboBox); + + settingPanel.add(new JLabel("题目数量:")); + countField = new JTextField("10"); + settingPanel.add(countField); + + mainPanel.add(settingPanel, BorderLayout.CENTER); + + // 按钮面板 + JPanel buttonPanel = new JPanel(new FlowLayout(FlowLayout.CENTER, 20, 10)); + buttonPanel.setBorder(BorderFactory.createEmptyBorder(10, 0, 0, 0)); + JButton startButton = new JButton("开始做题"); + JButton changePasswordButton = new JButton("修改密码"); + JButton logoutButton = new JButton("退出登录"); + JButton UnregisterButton = new JButton("删除账号"); + + buttonPanel.add(startButton); + buttonPanel.add(changePasswordButton); + buttonPanel.add(logoutButton); + buttonPanel.add(UnregisterButton); + + mainPanel.add(buttonPanel, BorderLayout.SOUTH); + + // 添加事件监听器 + startButton.addActionListener(new StartListener()); + changePasswordButton.addActionListener(e -> openChangePasswordFrame()); + logoutButton.addActionListener(e -> openLoginFrame()); + UnregisterButton.addActionListener(e-> UnregisterOperation()); + + add(mainPanel); + } + + private class StartListener implements ActionListener { + @Override + public void actionPerformed(ActionEvent e) { + String type = (String) typeComboBox.getSelectedItem(); + String countText = countField.getText().trim(); + + if (countText.isEmpty()) { + JOptionPane.showMessageDialog(Main_frame.this, + "请输入题目数量", "错误", JOptionPane.ERROR_MESSAGE); + return; + } + + int count; + try { + count = Integer.parseInt(countText); + } catch (NumberFormatException ex) { + JOptionPane.showMessageDialog(Main_frame.this, + "题目数量必须是数字", "错误", JOptionPane.ERROR_MESSAGE); + return; + } + + if (count < 10 || count > 30) { + JOptionPane.showMessageDialog(Main_frame.this, + "题目数量必须在10-30之间", "错误", JOptionPane.ERROR_MESSAGE); + return; + } + + // 创建考试服务 + Exam_service examService = new Exam_service(count, type, userService.find_user(email).get_id()); + openExamFrame(examService); + } + } + + private void openExamFrame(Exam_service examService) { + Exam_frame examFrame = new Exam_frame(examService, userService, email); + examFrame.setVisible(true); + this.dispose(); + } + + private void openChangePasswordFrame() { + JPasswordField oldPasswordField = new JPasswordField(); + JPasswordField newPasswordField = new JPasswordField(); + JPasswordField confirmPasswordField = new JPasswordField(); + + JPanel panel = new JPanel(new GridLayout(3, 2)); + panel.add(new JLabel("原密码:")); + panel.add(oldPasswordField); + panel.add(new JLabel("新密码:")); + panel.add(newPasswordField); + panel.add(new JLabel("确认新密码:")); + panel.add(confirmPasswordField); + + int result = JOptionPane.showConfirmDialog(this, panel, "修改密码", JOptionPane.OK_CANCEL_OPTION); + if (result == JOptionPane.OK_OPTION) { + String oldPassword = new String(oldPasswordField.getPassword()); + String newPassword = new String(newPasswordField.getPassword()); + String confirmPassword = new String(confirmPasswordField.getPassword()); + + if (!newPassword.equals(confirmPassword)) { + JOptionPane.showMessageDialog(this, + "两次输入的新密码不一致", "错误", JOptionPane.ERROR_MESSAGE); + return; + } + + String changeResult = userService.change_pwd(email, oldPassword, newPassword); + JOptionPane.showMessageDialog(this, changeResult, "修改密码", JOptionPane.INFORMATION_MESSAGE); + } + } + + private void openLoginFrame() { + Login_frame loginFrame = new Login_frame(userService); + loginFrame.setVisible(true); + this.dispose(); + } + + private void UnregisterOperation(){ + String result=userService.Unregister(email); + JOptionPane.showMessageDialog(this, result, "删除账号", JOptionPane.INFORMATION_MESSAGE); + openLoginFrame(); + } +} diff --git a/src/View/Register_frame.java b/src/View/Register_frame.java new file mode 100644 index 0000000..67efa98 --- /dev/null +++ b/src/View/Register_frame.java @@ -0,0 +1,167 @@ +package View; + +import Service.User_service; + +import javax.swing.*; +import java.awt.*; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; + +public class Register_frame extends JFrame { + private User_service userService; + private JTextField emailField; + private JTextField codeField; + private JTextField idField; + private JPasswordField passwordField; + private JPasswordField confirmPasswordField; + private JButton sendCodeButton; + private JButton registerButton; + private JButton backButton; + + public Register_frame(User_service userService) { + this.userService = userService; + initializeUI(); + } + + private void initializeUI() { + setTitle("注册"); + setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + setSize(500, 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, 20)); + mainPanel.add(titleLabel, BorderLayout.NORTH); + + // 表单面板 + JPanel formPanel = new JPanel(new GridLayout(5, 2, 10, 10)); + + // 输入邮箱 + formPanel.add(new JLabel("邮箱地址:")); + JPanel emailPanel = new JPanel(new BorderLayout()); + emailField = new JTextField(); + sendCodeButton = new JButton("发送验证码"); + emailPanel.add(emailField, BorderLayout.CENTER); + emailPanel.add(sendCodeButton, BorderLayout.EAST); + formPanel.add(emailPanel); + + // 验证码和密码 + formPanel.add(new JLabel("验证码:")); + codeField = new JTextField(); + formPanel.add(codeField); + + formPanel.add(new JLabel("用户名:")); + idField = new JTextField(); + formPanel.add(idField); + + formPanel.add(new JLabel("密码:")); + passwordField = new JPasswordField(); + formPanel.add(passwordField); + + formPanel.add(new JLabel("确认密码:")); + confirmPasswordField = new JPasswordField(); + formPanel.add(confirmPasswordField); + + // 密码要求说明 + JLabel passwordHint = new JLabel("密码要求: 6-20位,至少包含大小写字母和数字"); + passwordHint.setFont(new Font("微软雅黑", Font.PLAIN, 12)); + passwordHint.setForeground(Color.GRAY); + + mainPanel.add(formPanel, BorderLayout.CENTER); + mainPanel.add(passwordHint, BorderLayout.SOUTH); + + JPanel buttonPanel = new JPanel(new FlowLayout()); + registerButton = new JButton("完成注册"); + backButton = new JButton("返回登录"); + + buttonPanel.add(registerButton); + buttonPanel.add(backButton); + + add(buttonPanel, BorderLayout.SOUTH); + + setStep1State(); + + sendCodeButton.addActionListener(new SendCodeListener()); + registerButton.addActionListener(new RegisterListener()); + backButton.addActionListener(e -> openLoginFrame()); + + add(mainPanel); + } + + private void setStep1State() { + codeField.setEnabled(false); + passwordField.setEnabled(false); + confirmPasswordField.setEnabled(false); + registerButton.setEnabled(false); + } + + private void setStep2State() { + codeField.setEnabled(true); + passwordField.setEnabled(true); + confirmPasswordField.setEnabled(true); + registerButton.setEnabled(true); + sendCodeButton.setEnabled(false); + } + + private class SendCodeListener implements ActionListener { + @Override + public void actionPerformed(ActionEvent e) { + String email = emailField.getText().trim(); + String result = userService.register(email); + if (result.equals("验证码已发送")) { + JOptionPane.showMessageDialog(Register_frame.this, + "验证码已发送到您的邮箱,请查收", "成功", JOptionPane.INFORMATION_MESSAGE); + setStep2State(); + } else { + JOptionPane.showMessageDialog(Register_frame.this, + result, "错误", JOptionPane.ERROR_MESSAGE); + } + } + } + + private class RegisterListener implements ActionListener { + @Override + public void actionPerformed(ActionEvent e) { + String email = emailField.getText().trim(); + String id = idField.getText().trim(); + String code = codeField.getText().trim(); + String password = new String(passwordField.getPassword()); + //确认密码(输两次) + String confirmPassword = new String(confirmPasswordField.getPassword()); + + if (code.isEmpty() || password.isEmpty() || confirmPassword.isEmpty()) { + JOptionPane.showMessageDialog(Register_frame.this, + "请填写所有字段", "错误", JOptionPane.ERROR_MESSAGE); + return; + } + + if (!password.equals(confirmPassword)) { + JOptionPane.showMessageDialog(Register_frame.this, + "两次输入的密码不一致", "错误", JOptionPane.ERROR_MESSAGE); + return; + } + + String result = userService.check_register(email, code, password,id); + if (result.equals("注册成功")) { + JOptionPane.showMessageDialog(Register_frame.this, + "注册成功!", "成功", JOptionPane.INFORMATION_MESSAGE); + openLoginFrame(); + } else { + JOptionPane.showMessageDialog(Register_frame.this, + result, "注册失败", JOptionPane.ERROR_MESSAGE); + } + } + } + + private void openLoginFrame() { + Login_frame loginFrame = new Login_frame(userService); + loginFrame.setVisible(true); + this.dispose(); + } +} \ No newline at end of file diff --git a/src/View/Result_frame.java b/src/View/Result_frame.java new file mode 100644 index 0000000..5a3b418 --- /dev/null +++ b/src/View/Result_frame.java @@ -0,0 +1,82 @@ +package View; + +import Base.Exam_result; +import Service.Exam_service; +import Service.User_service; + +import javax.swing.*; +import java.awt.*; + +public class Result_frame extends JFrame { + private Exam_service examService; + private Exam_result result; + private User_service userService; + private String email; + + public Result_frame(Exam_service ex,Exam_result result, User_service userService, String email) { + this.examService=ex; + this.result = result; + this.userService = userService; + this.email = email; + initializeUI(); + } + + private void initializeUI() { + setTitle("考试结果"); + setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + setSize(500, 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 resultPanel = new JPanel(new GridLayout(5, 1, 10, 10)); + resultPanel.add(new JLabel("考试类型: " + result.getExamType())); + resultPanel.add(new JLabel("题目数量: " + result.getTotalQuestions())); + resultPanel.add(new JLabel("正确题目: " + result.getCorrectAnswers())); + resultPanel.add(new JLabel("得分: " + String.format("%.2f", result.getScore()))); + resultPanel.add(new JLabel("用时: " + result.getDuration())); + + mainPanel.add(resultPanel, BorderLayout.CENTER); + + // 按钮面板 + JPanel buttonPanel = new JPanel(new FlowLayout()); + JButton reviewButton =new JButton("查看错题"); + JButton mainMenuButton = new JButton("返回主菜单"); + JButton exitButton = new JButton("退出"); + + buttonPanel.add(reviewButton); + buttonPanel.add(mainMenuButton); + buttonPanel.add(exitButton); + + mainPanel.add(buttonPanel, BorderLayout.SOUTH); + + // 添加事件监听器 + reviewButton.addActionListener(e->openReviewFrame()); + mainMenuButton.addActionListener(e -> openMainFrame()); + exitButton.addActionListener(e -> System.exit(0)); + + add(mainPanel); + } + + private void openMainFrame() { + Main_frame mainFrame = new Main_frame(userService, email); + mainFrame.setVisible(true); + this.dispose(); + } + + private void openReviewFrame(){ + examService.set_now_index(0); + Review_frame reviewFrame= new Review_frame(examService,userService, email,result); + reviewFrame.setVisible(true); + this.dispose(); + } +} diff --git a/src/View/Review_frame.java b/src/View/Review_frame.java new file mode 100644 index 0000000..08a4ab2 --- /dev/null +++ b/src/View/Review_frame.java @@ -0,0 +1,148 @@ +package View; + +import Base.Exam_result; +import Base.Question; +import Service.Exam_service; +import Service.User_service; + +import javax.swing.*; +import java.awt.*; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; + +public class Review_frame extends JFrame{ + private Exam_service examService; + private User_service userService; + private String email; + private Exam_result examResult; + private JLabel questionLabel; + private JLabel[] optionLabel; + private JLabel progressLabel; + private JButton previousButton; + private JButton nextButton; + private JButton exitButton; + + public Review_frame(Exam_service examService, User_service userService, String email,Exam_result ex) { + this.examService = examService; + this.userService = userService; + this.email = email; + this.examResult = ex; + initializeUI(); + showQuestion(); + } + + private void initializeUI() { + setTitle("查看错题"); + setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + setSize(600, 400); + setLocationRelativeTo(null); + setResizable(false); + + // 主面板 + JPanel mainPanel = new JPanel(new BorderLayout(10, 10)); + mainPanel.setBorder(BorderFactory.createEmptyBorder(20, 20, 20, 20)); + + // 进度标签 + progressLabel = new JLabel(); + updateProgress(); + mainPanel.add(progressLabel, BorderLayout.NORTH); + + // 题目面板 + JPanel questionPanel = new JPanel(new BorderLayout()); + questionLabel = new JLabel(); + questionLabel.setFont(new Font("微软雅黑", Font.PLAIN, 16)); + questionPanel.add(questionLabel, BorderLayout.NORTH); + + // 选项面板 + JPanel optionsPanel = new JPanel(new GridLayout(4, 1, 10, 10)); + optionLabel = new JLabel[4]; + for (int i = 0; i < 4; i++) { + optionLabel[i] = new JLabel(); + optionLabel[i].setFont(new Font("微软雅黑", Font.PLAIN, 14)); + optionsPanel.add(optionLabel[i]); + } + + questionPanel.add(optionsPanel, BorderLayout.CENTER); + mainPanel.add(questionPanel, BorderLayout.CENTER); + + // 按钮面板 + JPanel buttonPanel = new JPanel(new FlowLayout()); + previousButton = new JButton("上一题"); + nextButton = new JButton("下一题"); + exitButton = new JButton("返回"); + + buttonPanel.add(previousButton); + buttonPanel.add(nextButton); + buttonPanel.add(exitButton); + + mainPanel.add(buttonPanel, BorderLayout.SOUTH); + + // 添加事件监听器 + previousButton.addActionListener(new Review_frame.PreviousListener()); + nextButton.addActionListener(new Review_frame.NextListener()); + exitButton.addActionListener(e->openResultFrame()); + + add(mainPanel); + } + + private void showQuestion() { + Question currentQuestion = examService.get_now_question(); + if (currentQuestion == null) { + return; + } + + questionLabel.setText(currentQuestion.getContent()); + if (examResult.getWrongQuestions().contains(examService.get_now_index())) { + for (int i = 0; i < 4; i++) { + String options = currentQuestion.getOptions(i); + if (options.equals(currentQuestion.getAnswer())){ + options=options+"√"; + } + else if (i==examService.get_user_answers().get(examService.get_now_index())){ + options=options+"×"; + } + optionLabel[i].setText(options); + } + } + else { + for (int i = 0; i < 4; i++) { + String options = currentQuestion.getOptions(i); + if (options.equals(currentQuestion.getAnswer())){ + options=options+"√"; + } + optionLabel[i].setText(options); + } + } + + updateProgress(); + } + + private void updateProgress() { + int current = examService.get_now_index() + 1; + int total = examService.get_paper().size(); + progressLabel.setText("进度: " + current + "/" + total); + } + + + private class PreviousListener implements ActionListener { + @Override + public void actionPerformed(ActionEvent e) { + examService.set_now_index(-1); + showQuestion(); + } + } + + private class NextListener implements ActionListener { + @Override + public void actionPerformed(ActionEvent e) { + examService.set_now_index(1); + showQuestion(); + } + } + + private void openResultFrame() { + Result_frame resultFrame = new Result_frame(examService, examResult, userService, email); + resultFrame.setVisible(true); + this.dispose(); + } +}