From 7dfe5949163a17c78b832c8d886dc5b23d61ef73 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=88=98=E6=98=9F=E5=AE=87?= <974058674@qq.com> Date: Sat, 11 Oct 2025 00:54:37 +0800 Subject: [PATCH] first commit --- AppLauncher.java | 29 +++ MainFrame.java | 557 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 586 insertions(+) create mode 100644 AppLauncher.java create mode 100644 MainFrame.java diff --git a/AppLauncher.java b/AppLauncher.java new file mode 100644 index 0000000..d5351d7 --- /dev/null +++ b/AppLauncher.java @@ -0,0 +1,29 @@ +package View; +import javax.swing.*; +import Service.Exam_service; +import Service.User_service; + +public class AppLauncher { + public static void main(String[] args) { + // 设置中文显示 + setUIFont(); + + SwingUtilities.invokeLater(() -> { + MainFrame frame = new MainFrame(); + frame.setVisible(true); + }); + } + + private static void setUIFont() { + try { + UIManager.put("Button.font", new javax.swing.plaf.FontUIResource("微软雅黑", java.awt.Font.PLAIN, 13)); + UIManager.put("Label.font", new javax.swing.plaf.FontUIResource("微软雅黑", java.awt.Font.PLAIN, 13)); + UIManager.put("TextField.font", new javax.swing.plaf.FontUIResource("微软雅黑", java.awt.Font.PLAIN, 13)); + UIManager.put("PasswordField.font", new javax.swing.plaf.FontUIResource("微软雅黑", java.awt.Font.PLAIN, 13)); + UIManager.put("TextArea.font", new javax.swing.plaf.FontUIResource("微软雅黑", java.awt.Font.PLAIN, 13)); + UIManager.put("RadioButton.font", new javax.swing.plaf.FontUIResource("微软雅黑", java.awt.Font.PLAIN, 13)); + } catch (Exception e) { + e.printStackTrace(); + } + } +} diff --git a/MainFrame.java b/MainFrame.java new file mode 100644 index 0000000..3f190fe --- /dev/null +++ b/MainFrame.java @@ -0,0 +1,557 @@ +package View; + +import Service.User_service; +import Service.Exam_service; + +import javax.swing.*; +import java.awt.*; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; + +public class MainFrame extends JFrame { + private User_service userService; + private Exam_service examService; + private CardLayout cardLayout; + private JPanel mainPanel; + + // 登录面板组件 + private JTextField loginEmailField; + private JPasswordField loginPasswordField; + + // 注册面板组件 + private JTextField regEmailField; + private JTextField regCodeField; + private JPasswordField regPasswordField; + private JPasswordField regConfirmPasswordField; + + // 考试面板组件 + private JLabel questionLabel; + private JRadioButton[] optionButtons; + private ButtonGroup optionGroup; + private JLabel questionNumberLabel; + private JLabel examInfoLabel; + + // 结果面板组件 + private JLabel resultLabel; + + public MainFrame() { + userService = new User_service(); + examService = new Exam_service(); + initializeUI(); + } + + private void initializeUI() { + setTitle("数学学习软件"); + setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + setSize(800, 600); + setLocationRelativeTo(null); + + cardLayout = new CardLayout(); + mainPanel = new JPanel(cardLayout); + + createLoginPanel(); + createRegisterPanel(); + createGradeSelectionPanel(); + createExamPanel(); + createResultPanel(); + createPasswordChangePanel(); + + add(mainPanel); + showLoginPanel(); + } + + private void createLoginPanel() { + JPanel panel = new JPanel(new BorderLayout(10, 10)); + panel.setBorder(BorderFactory.createEmptyBorder(50, 100, 50, 100)); + + // 标题 + JLabel titleLabel = new JLabel("数学学习软件", JLabel.CENTER); + titleLabel.setFont(new Font("微软雅黑", Font.BOLD, 24)); + panel.add(titleLabel, BorderLayout.NORTH); + + // 表单区域 + JPanel formPanel = new JPanel(new GridLayout(3, 2, 15, 15)); + formPanel.setBorder(BorderFactory.createEmptyBorder(30, 50, 30, 50)); + + formPanel.add(new JLabel("邮箱:", JLabel.RIGHT)); + loginEmailField = new JTextField(); + formPanel.add(loginEmailField); + + formPanel.add(new JLabel("密码:", JLabel.RIGHT)); + loginPasswordField = new JPasswordField(); + formPanel.add(loginPasswordField); + + panel.add(formPanel, BorderLayout.CENTER); + + // 按钮区域 + JPanel buttonPanel = new JPanel(new FlowLayout(FlowLayout.CENTER, 20, 10)); + + JButton loginButton = createStyledButton("登录", new Color(70, 130, 180)); + loginButton.addActionListener(e -> login()); + buttonPanel.add(loginButton); + + JButton registerButton = createStyledButton("注册账号", new Color(60, 179, 113)); + registerButton.addActionListener(e -> showRegisterPanel()); + buttonPanel.add(registerButton); + + panel.add(buttonPanel, BorderLayout.SOUTH); + + mainPanel.add(panel, "Login"); + } + + private void createRegisterPanel() { + JPanel panel = new JPanel(new BorderLayout(10, 10)); + panel.setBorder(BorderFactory.createEmptyBorder(30, 80, 30, 80)); + + JLabel titleLabel = new JLabel("用户注册", JLabel.CENTER); + titleLabel.setFont(new Font("微软雅黑", Font.BOLD, 20)); + panel.add(titleLabel, BorderLayout.NORTH); + + JPanel formPanel = new JPanel(new GridLayout(5, 2, 15, 15)); + formPanel.setBorder(BorderFactory.createEmptyBorder(20, 50, 20, 50)); + + formPanel.add(new JLabel("邮箱:", JLabel.RIGHT)); + regEmailField = new JTextField(); + formPanel.add(regEmailField); + + formPanel.add(new JLabel("验证码:", JLabel.RIGHT)); + JPanel codePanel = new JPanel(new BorderLayout(5, 0)); + regCodeField = new JTextField(); + codePanel.add(regCodeField, BorderLayout.CENTER); + + JButton sendCodeButton = new JButton("发送验证码"); + sendCodeButton.setFont(new Font("微软雅黑", Font.PLAIN, 10)); + sendCodeButton.addActionListener(e -> sendVerificationCode()); + codePanel.add(sendCodeButton, BorderLayout.EAST); + formPanel.add(codePanel); + + formPanel.add(new JLabel("密码:", JLabel.RIGHT)); + regPasswordField = new JPasswordField(); + formPanel.add(regPasswordField); + + formPanel.add(new JLabel("确认密码:", JLabel.RIGHT)); + regConfirmPasswordField = new JPasswordField(); + formPanel.add(regConfirmPasswordField); + + panel.add(formPanel, BorderLayout.CENTER); + + JPanel buttonPanel = new JPanel(new FlowLayout(FlowLayout.CENTER, 20, 10)); + + JButton registerButton = createStyledButton("注册", new Color(60, 179, 113)); + registerButton.addActionListener(e -> register()); + buttonPanel.add(registerButton); + + JButton backButton = createStyledButton("返回登录", new Color(192, 192, 192)); + backButton.addActionListener(e -> showLoginPanel()); + buttonPanel.add(backButton); + + panel.add(buttonPanel, BorderLayout.SOUTH); + + mainPanel.add(panel, "Register"); + } + + private void createGradeSelectionPanel() { + JPanel panel = new JPanel(new BorderLayout(10, 10)); + panel.setBorder(BorderFactory.createEmptyBorder(50, 100, 50, 100)); + + JLabel titleLabel = new JLabel("选择学习阶段", JLabel.CENTER); + titleLabel.setFont(new Font("微软雅黑", Font.BOLD, 24)); + panel.add(titleLabel, BorderLayout.NORTH); + + JPanel gradePanel = new JPanel(new GridLayout(4, 1, 20, 20)); + gradePanel.setBorder(BorderFactory.createEmptyBorder(50, 100, 50, 100)); + + JButton primaryButton = createGradeButton("小学", new Color(255, 182, 193)); + primaryButton.addActionListener(e -> startExam(0, "小学")); + gradePanel.add(primaryButton); + + JButton juniorButton = createGradeButton("初中", new Color(135, 206, 250)); + juniorButton.addActionListener(e -> startExam(1, "初中")); + gradePanel.add(juniorButton); + + JButton seniorButton = createGradeButton("高中", new Color(152, 251, 152)); + seniorButton.addActionListener(e -> startExam(2, "高中")); + gradePanel.add(seniorButton); + + panel.add(gradePanel, BorderLayout.CENTER); + + JPanel bottomPanel = new JPanel(new FlowLayout(FlowLayout.CENTER, 20, 10)); + + JButton changePasswordButton = createStyledButton("修改密码", new Color(255, 165, 0)); + changePasswordButton.addActionListener(e -> showPasswordChangePanel()); + bottomPanel.add(changePasswordButton); + + JButton logoutButton = createStyledButton("退出登录", new Color(220, 20, 60)); + logoutButton.addActionListener(e -> logout()); + bottomPanel.add(logoutButton); + + panel.add(bottomPanel, BorderLayout.SOUTH); + + mainPanel.add(panel, "GradeSelection"); + } + + private void createExamPanel() { + JPanel panel = new JPanel(new BorderLayout(10, 10)); + panel.setBorder(BorderFactory.createEmptyBorder(20, 40, 20, 40)); + + // 顶部信息栏 + JPanel topPanel = new JPanel(new BorderLayout()); + questionNumberLabel = new JLabel("", JLabel.LEFT); + questionNumberLabel.setFont(new Font("微软雅黑", Font.BOLD, 16)); + + examInfoLabel = new JLabel("", JLabel.RIGHT); + examInfoLabel.setFont(new Font("微软雅黑", Font.PLAIN, 14)); + + topPanel.add(questionNumberLabel, BorderLayout.WEST); + topPanel.add(examInfoLabel, BorderLayout.EAST); + panel.add(topPanel, BorderLayout.NORTH); + + // 题目区域 + JPanel questionPanel = new JPanel(new BorderLayout(10, 20)); + questionPanel.setBorder(BorderFactory.createEmptyBorder(30, 50, 30, 50)); + + questionLabel = new JLabel("", JLabel.CENTER); + questionLabel.setFont(new Font("微软雅黑", Font.PLAIN, 18)); + questionPanel.add(questionLabel, BorderLayout.NORTH); + + // 选项区域 + JPanel optionsPanel = new JPanel(new GridLayout(4, 1, 10, 10)); + optionsPanel.setBorder(BorderFactory.createEmptyBorder(20, 100, 20, 100)); + + optionButtons = new JRadioButton[4]; + optionGroup = new ButtonGroup(); + String[] optionLabels = {"A. ", "B. ", "C. ", "D. "}; + + for (int i = 0; i < 4; i++) { + JPanel optionPanel = new JPanel(new BorderLayout()); + optionButtons[i] = new JRadioButton(); + optionButtons[i].setFont(new Font("微软雅黑", Font.PLAIN, 16)); + optionGroup.add(optionButtons[i]); + + JLabel optionLabel = new JLabel(optionLabels[i]); + optionLabel.setFont(new Font("微软雅黑", Font.BOLD, 16)); + optionLabel.setPreferredSize(new Dimension(30, 25)); + + optionPanel.add(optionLabel, BorderLayout.WEST); + optionPanel.add(optionButtons[i], BorderLayout.CENTER); + optionsPanel.add(optionPanel); + } + + questionPanel.add(optionsPanel, BorderLayout.CENTER); + panel.add(questionPanel, BorderLayout.CENTER); + + // 提交按钮 + JPanel bottomPanel = new JPanel(new FlowLayout(FlowLayout.CENTER)); + JButton submitButton = createStyledButton("提交答案", new Color(70, 130, 180)); + submitButton.addActionListener(e -> submitAnswer()); + bottomPanel.add(submitButton); + + panel.add(bottomPanel, BorderLayout.SOUTH); + + mainPanel.add(panel, "Exam"); + } + + private void createResultPanel() { + JPanel panel = new JPanel(new BorderLayout(10, 10)); + panel.setBorder(BorderFactory.createEmptyBorder(50, 100, 50, 100)); + + resultLabel = new JLabel("", JLabel.CENTER); + resultLabel.setFont(new Font("微软雅黑", Font.BOLD, 24)); + panel.add(resultLabel, BorderLayout.CENTER); + + JPanel buttonPanel = new JPanel(new FlowLayout(FlowLayout.CENTER, 30, 20)); + + JButton continueButton = createStyledButton("继续做题", new Color(60, 179, 113)); + continueButton.addActionListener(e -> showGradeSelectionPanel()); + + JButton exitButton = createStyledButton("退出程序", new Color(220, 20, 60)); + exitButton.addActionListener(e -> System.exit(0)); + + buttonPanel.add(continueButton); + buttonPanel.add(exitButton); + panel.add(buttonPanel, BorderLayout.SOUTH); + + mainPanel.add(panel, "Result"); + } + + private void createPasswordChangePanel() { + JPanel panel = new JPanel(new BorderLayout(10, 10)); + panel.setBorder(BorderFactory.createEmptyBorder(50, 100, 50, 100)); + + JLabel titleLabel = new JLabel("修改密码", JLabel.CENTER); + titleLabel.setFont(new Font("微软雅黑", Font.BOLD, 20)); + panel.add(titleLabel, BorderLayout.NORTH); + + JPanel formPanel = new JPanel(new GridLayout(4, 2, 15, 15)); + formPanel.setBorder(BorderFactory.createEmptyBorder(30, 80, 30, 80)); + + formPanel.add(new JLabel("原密码:", JLabel.RIGHT)); + JPasswordField oldPasswordField = new JPasswordField(); + formPanel.add(oldPasswordField); + + formPanel.add(new JLabel("新密码:", JLabel.RIGHT)); + JPasswordField newPasswordField = new JPasswordField(); + formPanel.add(newPasswordField); + + formPanel.add(new JLabel("确认新密码:", JLabel.RIGHT)); + JPasswordField confirmPasswordField = new JPasswordField(); + formPanel.add(confirmPasswordField); + + panel.add(formPanel, BorderLayout.CENTER); + + JPanel buttonPanel = new JPanel(new FlowLayout(FlowLayout.CENTER, 20, 10)); + + JButton changeButton = createStyledButton("确认修改", new Color(60, 179, 113)); + changeButton.addActionListener(e -> { + String oldPassword = new String(oldPasswordField.getPassword()); + String newPassword = new String(newPasswordField.getPassword()); + String confirmPassword = new String(confirmPasswordField.getPassword()); + changePassword(oldPassword, newPassword, confirmPassword); + }); + buttonPanel.add(changeButton); + + JButton backButton = createStyledButton("返回", new Color(192, 192, 192)); + backButton.addActionListener(e -> showGradeSelectionPanel()); + buttonPanel.add(backButton); + + panel.add(buttonPanel, BorderLayout.SOUTH); + + mainPanel.add(panel, "PasswordChange"); + } + + // 工具方法:创建样式化按钮 + private JButton createStyledButton(String text, Color bgColor) { + JButton button = new JButton(text); + button.setFont(new Font("微软雅黑", Font.BOLD, 14)); + button.setBackground(bgColor); + button.setForeground(Color.WHITE); + button.setFocusPainted(false); + button.setBorder(BorderFactory.createEmptyBorder(10, 20, 10, 20)); + return button; + } + + // 工具方法:创建年级选择按钮 + private JButton createGradeButton(String text, Color bgColor) { + JButton button = new JButton(text); + button.setFont(new Font("微软雅黑", Font.BOLD, 18)); + button.setBackground(bgColor); + button.setForeground(Color.BLACK); + button.setFocusPainted(false); + button.setBorder(BorderFactory.createEmptyBorder(20, 0, 20, 0)); + return button; + } + + // 界面显示方法 + private void showLoginPanel() { + loginEmailField.setText(""); + loginPasswordField.setText(""); + cardLayout.show(mainPanel, "Login"); + } + + private void showRegisterPanel() { + regEmailField.setText(""); + regCodeField.setText(""); + regPasswordField.setText(""); + regConfirmPasswordField.setText(""); + cardLayout.show(mainPanel, "Register"); + } + + private void showGradeSelectionPanel() { + cardLayout.show(mainPanel, "GradeSelection"); + } + + private void showPasswordChangePanel() { + cardLayout.show(mainPanel, "PasswordChange"); + } + + // 业务逻辑方法 + private void login() { + String email = loginEmailField.getText().trim(); + String password = new String(loginPasswordField.getPassword()); + + if (email.isEmpty() || password.isEmpty()) { + JOptionPane.showMessageDialog(this, "请输入邮箱和密码"); + return; + } + + if (userService.login(email, password)) { + showGradeSelectionPanel(); + } else { + JOptionPane.showMessageDialog(this, "登录失败,请检查邮箱和密码"); + } + } + + private void sendVerificationCode() { + String email = regEmailField.getText().trim(); + if (email.isEmpty()) { + JOptionPane.showMessageDialog(this, "请输入邮箱地址"); + return; + } + + if (userService.sendVerificationCode(email)) { + JOptionPane.showMessageDialog(this, "验证码已发送到您的邮箱,请查收"); + } else { + JOptionPane.showMessageDialog(this, "验证码发送失败,请检查邮箱地址或稍后重试"); + } + } + + private void register() { + String email = regEmailField.getText().trim(); + String code = regCodeField.getText().trim(); + String password = new String(regPasswordField.getPassword()); + String confirmPassword = new String(regConfirmPasswordField.getPassword()); + + if (email.isEmpty() || code.isEmpty() || password.isEmpty()) { + JOptionPane.showMessageDialog(this, "请填写所有字段"); + return; + } + + if (!password.equals(confirmPassword)) { + JOptionPane.showMessageDialog(this, "两次输入的密码不一致"); + return; + } + + if (userService.completeRegistration(email, code, password)) { + JOptionPane.showMessageDialog(this, "注册成功,请登录"); + showLoginPanel(); + } else { + JOptionPane.showMessageDialog(this, "注册失败,请检查验证码和密码格式\n密码要求:6-10位,包含大小写字母和数字"); + } + } + + private void startExam(int gradeLevel, String gradeName) { + String input = JOptionPane.showInputDialog(this, + "请输入" + gradeName + "题目数量:", "题目数量", JOptionPane.QUESTION_MESSAGE); + + if (input == null) return; // 用户取消 + + try { + int count = Integer.parseInt(input.trim()); + if (count <= 0) { + JOptionPane.showMessageDialog(this, "题目数量必须大于0"); + return; + } + + if (count > 100) { + JOptionPane.showMessageDialog(this, "题目数量不能超过100"); + return; + } + + examService.startExam(gradeLevel, count); + showNextQuestion(); + cardLayout.show(mainPanel, "Exam"); + } catch (NumberFormatException e) { + JOptionPane.showMessageDialog(this, "请输入有效的数字"); + } + } + + private void showNextQuestion() { + Question question = examService.getCurrentQuestion(); + if (question != null) { + questionNumberLabel.setText(String.format("第 %d 题 / 共 %d 题", + examService.getCurrentQuestionNumber(), + examService.getTotalQuestions())); + + examInfoLabel.setText(getGradeName(question.getGradeLevel()) + "数学题"); + + questionLabel.setText("
" + question.getQuestionText() + "
"); + + java.util.List options = question.getOptions(); + String[] optionLetters = {"A", "B", "C", "D"}; + for (int i = 0; i < 4; i++) { + optionButtons[i].setText(optionLetters[i] + ". " + options.get(i)); + } + + optionGroup.clearSelection(); + } + } + + private String getGradeName(int gradeLevel) { + switch (gradeLevel) { + case 0: return "小学"; + case 1: return "初中"; + case 2: return "高中"; + default: return "未知"; + } + } + + private void submitAnswer() { + int selectedOption = -1; + for (int i = 0; i < 4; i++) { + if (optionButtons[i].isSelected()) { + selectedOption = i; + break; + } + } + + if (selectedOption == -1) { + JOptionPane.showMessageDialog(this, "请选择一个答案"); + return; + } + + examService.submitAnswer(selectedOption); + + if (examService.hasNextQuestion()) { + showNextQuestion(); + } else { + showResult(); + } + } + + private void showResult() { + ExamResult result = examService.getExamResult(); + String gradeName = getGradeName(result.getGradeLevel()); + + String resultText = String.format( + "
" + + "

%s数学测试完成!

" + + "

%s

" + + "

正确题数: %d / %d

" + + "

得分: %.1f

" + + "
", + gradeName, result.toString(), result.getCorrectAnswers(), + result.getTotalQuestions(), result.getScore() + ); + + resultLabel.setText(resultText); + cardLayout.show(mainPanel, "Result"); + } + + private void changePassword(String oldPassword, String newPassword, String confirmPassword) { + if (oldPassword.isEmpty() || newPassword.isEmpty() || confirmPassword.isEmpty()) { + JOptionPane.showMessageDialog(this, "请填写所有字段"); + return; + } + + if (!newPassword.equals(confirmPassword)) { + JOptionPane.showMessageDialog(this, "两次输入的新密码不一致"); + return; + } + + if (userService.changePassword(oldPassword, newPassword)) { + JOptionPane.showMessageDialog(this, "密码修改成功"); + showGradeSelectionPanel(); + } else { + JOptionPane.showMessageDialog(this, "密码修改失败,请检查原密码和新密码格式\n新密码要求:6-10位,包含大小写字母和数字"); + } + } + + private void logout() { + userService.logout(); + showLoginPanel(); + } + + public static void main(String[] args) { + // 设置系统样式 + try { + UIManager.setLookAndFeel(UIManager.getSystemLookAndFeel()); + } catch (Exception e) { + e.printStackTrace(); + } + + SwingUtilities.invokeLater(() -> { + MainFrame frame = new MainFrame(); + frame.setVisible(true); + }); + } +}