Compare commits

...

3 Commits
main ... lyq

Author SHA1 Message Date
LYQ c842e7f94f 更新了中央显示
4 months ago
LYQ 05dbc0b18a 前端2.0带邮箱
4 months ago
LYQ add58d0a32 前端1.0
4 months ago

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectRootManager" version="2" languageLevel="JDK_1_8" default="true" project-jdk-name="corretto-1.8" project-jdk-type="JavaSDK">
<component name="ProjectRootManager" version="2" languageLevel="JDK_17" project-jdk-name="corretto-17" project-jdk-type="JavaSDK">
<output url="file://$PROJECT_DIR$/out" />
</component>
</project>

@ -0,0 +1,124 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="Palette2">
<group name="Swing">
<item class="com.intellij.uiDesigner.HSpacer" tooltip-text="Horizontal Spacer" icon="/com/intellij/uiDesigner/icons/hspacer.svg" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="1" hsize-policy="6" anchor="0" fill="1" />
</item>
<item class="com.intellij.uiDesigner.VSpacer" tooltip-text="Vertical Spacer" icon="/com/intellij/uiDesigner/icons/vspacer.svg" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="6" hsize-policy="1" anchor="0" fill="2" />
</item>
<item class="javax.swing.JPanel" icon="/com/intellij/uiDesigner/icons/panel.svg" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="3" hsize-policy="3" anchor="0" fill="3" />
</item>
<item class="javax.swing.JScrollPane" icon="/com/intellij/uiDesigner/icons/scrollPane.svg" removable="false" auto-create-binding="false" can-attach-label="true">
<default-constraints vsize-policy="7" hsize-policy="7" anchor="0" fill="3" />
</item>
<item class="javax.swing.JButton" icon="/com/intellij/uiDesigner/icons/button.svg" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="3" anchor="0" fill="1" />
<initial-values>
<property name="text" value="Button" />
</initial-values>
</item>
<item class="javax.swing.JRadioButton" icon="/com/intellij/uiDesigner/icons/radioButton.svg" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="3" anchor="8" fill="0" />
<initial-values>
<property name="text" value="RadioButton" />
</initial-values>
</item>
<item class="javax.swing.JCheckBox" icon="/com/intellij/uiDesigner/icons/checkBox.svg" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="3" anchor="8" fill="0" />
<initial-values>
<property name="text" value="CheckBox" />
</initial-values>
</item>
<item class="javax.swing.JLabel" icon="/com/intellij/uiDesigner/icons/label.svg" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="0" anchor="8" fill="0" />
<initial-values>
<property name="text" value="Label" />
</initial-values>
</item>
<item class="javax.swing.JTextField" icon="/com/intellij/uiDesigner/icons/textField.svg" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1">
<preferred-size width="150" height="-1" />
</default-constraints>
</item>
<item class="javax.swing.JPasswordField" icon="/com/intellij/uiDesigner/icons/passwordField.svg" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1">
<preferred-size width="150" height="-1" />
</default-constraints>
</item>
<item class="javax.swing.JFormattedTextField" icon="/com/intellij/uiDesigner/icons/formattedTextField.svg" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1">
<preferred-size width="150" height="-1" />
</default-constraints>
</item>
<item class="javax.swing.JTextArea" icon="/com/intellij/uiDesigner/icons/textArea.svg" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
<preferred-size width="150" height="50" />
</default-constraints>
</item>
<item class="javax.swing.JTextPane" icon="/com/intellij/uiDesigner/icons/textPane.svg" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
<preferred-size width="150" height="50" />
</default-constraints>
</item>
<item class="javax.swing.JEditorPane" icon="/com/intellij/uiDesigner/icons/editorPane.svg" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
<preferred-size width="150" height="50" />
</default-constraints>
</item>
<item class="javax.swing.JComboBox" icon="/com/intellij/uiDesigner/icons/comboBox.svg" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="0" hsize-policy="2" anchor="8" fill="1" />
</item>
<item class="javax.swing.JTable" icon="/com/intellij/uiDesigner/icons/table.svg" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
<preferred-size width="150" height="50" />
</default-constraints>
</item>
<item class="javax.swing.JList" icon="/com/intellij/uiDesigner/icons/list.svg" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="6" hsize-policy="2" anchor="0" fill="3">
<preferred-size width="150" height="50" />
</default-constraints>
</item>
<item class="javax.swing.JTree" icon="/com/intellij/uiDesigner/icons/tree.svg" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
<preferred-size width="150" height="50" />
</default-constraints>
</item>
<item class="javax.swing.JTabbedPane" icon="/com/intellij/uiDesigner/icons/tabbedPane.svg" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="3" hsize-policy="3" anchor="0" fill="3">
<preferred-size width="200" height="200" />
</default-constraints>
</item>
<item class="javax.swing.JSplitPane" icon="/com/intellij/uiDesigner/icons/splitPane.svg" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="3" hsize-policy="3" anchor="0" fill="3">
<preferred-size width="200" height="200" />
</default-constraints>
</item>
<item class="javax.swing.JSpinner" icon="/com/intellij/uiDesigner/icons/spinner.svg" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1" />
</item>
<item class="javax.swing.JSlider" icon="/com/intellij/uiDesigner/icons/slider.svg" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1" />
</item>
<item class="javax.swing.JSeparator" icon="/com/intellij/uiDesigner/icons/separator.svg" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3" />
</item>
<item class="javax.swing.JProgressBar" icon="/com/intellij/uiDesigner/icons/progressbar.svg" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="6" anchor="0" fill="1" />
</item>
<item class="javax.swing.JToolBar" icon="/com/intellij/uiDesigner/icons/toolbar.svg" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="6" anchor="0" fill="1">
<preferred-size width="-1" height="20" />
</default-constraints>
</item>
<item class="javax.swing.JToolBar$Separator" icon="/com/intellij/uiDesigner/icons/toolbarSeparator.svg" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="0" anchor="0" fill="1" />
</item>
<item class="javax.swing.JScrollBar" icon="/com/intellij/uiDesigner/icons/scrollbar.svg" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="6" hsize-policy="0" anchor="0" fill="2" />
</item>
</group>
</component>
</project>

@ -8,7 +8,19 @@
<content url="file://$MODULE_DIR$">
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="jdk" jdkName="corretto-17" jdkType="JavaSDK" />
<orderEntry type="sourceFolder" forTests="false" />
<orderEntry type="library" exported="" name="lib" level="application" />
<orderEntry type="library" exported="" name="l" level="application" />
<orderEntry type="module-library" exported="">
<library>
<CLASSES>
<root url="file://$MODULE_DIR$/lib" />
</CLASSES>
<JAVADOC />
<SOURCES />
<jarDirectory url="file://$MODULE_DIR$/lib" recursive="false" />
</library>
</orderEntry>
</component>
</module>

Binary file not shown.

Binary file not shown.

@ -1,30 +0,0 @@
package account;
public class Account {
private String userName;
private String password;
private String userType;
public Account(String userName, String password,String userType) {
this.userName = userName;
this.password = password;
this.userType = userType;
}
public String getUserType() {
return userType;
}
public String getUserName() {
return userName;
}
public String getPassword() {
return password;
}
public void setUserType(String userType) {
this.userType = userType;
}
}

@ -1,5 +0,0 @@
package account;
public interface AccountService {
Account login(String username, String password);
}

@ -1,30 +0,0 @@
package account;
import java.util.HashMap;
import java.util.Map;
public class SimpleAccountService implements AccountService {
private static final Map<String, Account> accounts = new HashMap<>();
static {
accounts.put("张三1", new Account("张三1", "123", "小学"));
accounts.put("张三2", new Account("张三2", "123", "小学"));
accounts.put("张三3", new Account("张三3", "123", "小学"));
accounts.put("李四1", new Account("李四1", "123", "初中"));
accounts.put("李四2", new Account("李四2", "123", "初中"));
accounts.put("李四3", new Account("李四3", "123", "初中"));
accounts.put("王五1", new Account("王五1", "123", "高中"));
accounts.put("王五2", new Account("王五2", "123", "高中"));
accounts.put("王五3", new Account("王五3", "123", "高中"));
}
@Override
public Account login(String username, String password) {
Account account = accounts.get(username);
if (account != null && account.getPassword().equals(password)) {
return account;
}
return null;
}
}

@ -0,0 +1,110 @@
package com.student.mathquiz;
import com.student.mathquiz.view.*; // 导入所有 view controller
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Scene;
import javafx.scene.layout.AnchorPane;
import javafx.scene.layout.BorderPane;
import javafx.stage.Stage;
import java.io.IOException;
public class MainApp extends Application {
private Stage primaryStage;
private BorderPane rootLayout;
// start 方法修改后
@Override
public void start(Stage primaryStage) {
this.primaryStage = primaryStage;
this.primaryStage.setTitle("小初高数学学习软件");
initRootLayout();
showLoginView();
this.primaryStage.centerOnScreen();
this.primaryStage.show();
}
public void initRootLayout() {
try {
FXMLLoader loader = new FXMLLoader(MainApp.class.getResource("view/RootLayout.fxml"));
rootLayout = loader.load();
Scene scene = new Scene(rootLayout);
primaryStage.setScene(scene);
//primaryStage.show();
} catch (IOException e) {
e.printStackTrace();
}
}
public void showLoginView() {
try {
FXMLLoader loader = new FXMLLoader(MainApp.class.getResource("view/LoginView.fxml"));
AnchorPane view = loader.load();
rootLayout.setCenter(view);
LoginViewController controller = loader.getController();
controller.setMainApp(this);
} catch (IOException e) {
e.printStackTrace();
}
}
public void showRegisterView() {
try {
FXMLLoader loader = new FXMLLoader(MainApp.class.getResource("view/RegisterView.fxml"));
AnchorPane view = loader.load();
rootLayout.setCenter(view);
RegisterViewController controller = loader.getController();
controller.setMainApp(this);
} catch (IOException e) {
e.printStackTrace();
}
}
public void showMainMenuView() {
try {
FXMLLoader loader = new FXMLLoader(MainApp.class.getResource("view/MainMenuView.fxml"));
AnchorPane view = loader.load();
rootLayout.setCenter(view);
MainMenuViewController controller = loader.getController();
controller.setMainApp(this);
} catch (IOException e) {
e.printStackTrace();
}
}
// ★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★
// ★ 看这里!我们现在真正地实现了这两个方法! ★
// ★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★
public void showQuizView() {
try {
FXMLLoader loader = new FXMLLoader(MainApp.class.getResource("view/QuizView.fxml"));
AnchorPane view = loader.load();
rootLayout.setCenter(view);
QuizViewController controller = loader.getController();
controller.setMainApp(this);
} catch (IOException e) {
e.printStackTrace();
}
}
public void showScoreView() {
try {
FXMLLoader loader = new FXMLLoader(MainApp.class.getResource("view/ScoreView.fxml"));
AnchorPane view = loader.load();
rootLayout.setCenter(view);
ScoreViewController controller = loader.getController();
controller.setMainApp(this);
// 我们可以先给一个假分数,让你看到效果
controller.setScore(80);
} catch (IOException e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
launch(args);
}
}

@ -0,0 +1,83 @@
package com.student.mathquiz.view;
import jakarta.mail.*;
import jakarta.mail.internet.InternetAddress;
import jakarta.mail.internet.MimeMessage;
import java.util.Properties;
import java.util.Random;
public class EmailService {
// ★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★
// ★ 把这里换成你自己的发件人邮箱和授权码! ★
// ★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★
private static final String SENDER_EMAIL = "3048494657@qq.com";
private static final String SENDER_AUTHORIZATION_CODE = "ymnbezwjzrnfdgih";
/**
* 6.
* @return 6
*/
public static String generateVerificationCode() {
Random random = new Random();
int code = 100000 + random.nextInt(900000); // 保证是6位数
return String.valueOf(code);
}
/**
* .
* @param recipientEmail
* @param code
* @return true, false
*/
public static boolean sendVerificationEmail(String recipientEmail, String code) {
// 1. 配置邮件服务器属性
Properties props = new Properties();
props.put("mail.smtp.host", "smtp.qq.com"); // QQ邮箱的SMTP服务器地址
props.put("mail.smtp.port", "587"); // SMTP服务器端口 (使用TLS加密)
props.put("mail.smtp.auth", "true"); // 需要身份验证
props.put("mail.smtp.starttls.enable", "true"); // 启用TLS加密
// 2. 创建认证器,用于登录邮箱
Authenticator authenticator = new Authenticator() {
@Override
protected PasswordAuthentication getPasswordAuthentication() {
return new PasswordAuthentication(SENDER_EMAIL, SENDER_AUTHORIZATION_CODE);
}
};
// 3. 获取邮件会话 Session
Session session = Session.getInstance(props, authenticator);
try {
// 4. 创建邮件消息 MimeMessage
MimeMessage message = new MimeMessage(session);
// 设置发件人
message.setFrom(new InternetAddress(SENDER_EMAIL));
// 设置收件人
message.setRecipients(Message.RecipientType.TO, InternetAddress.parse(recipientEmail));
// 设置邮件主题
message.setSubject("【数学学习软件】您的注册验证码");
// 设置邮件正文内容
message.setText("尊敬的用户,您好!\n\n您的注册验证码是" + code + "\n\n请在5分钟内完成注册。如果不是您本人操作请忽略此邮件。\n\n(此为系统自动发送,请勿回复)");
// 5. 发送邮件!
Transport.send(message);
System.out.println("验证码邮件发送成功!");
return true;
} catch (MessagingException e) {
e.printStackTrace();
System.out.println("邮件发送失败!");
return false;
}
}
// 你可以写一个临时的 main 方法来测试它!
/* public static void main(String[] args) {
String code = generateVerificationCode();
// ★★★ 把这里换成你自己的另一个邮箱来接收测试邮件 ★★★
sendVerificationEmail("lyqqqq1214@163.com", code);
}*/
}

@ -0,0 +1,16 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- LoginView.fxml -->
<?import javafx.geometry.Insets?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<?import javafx.scene.text.Font?>
<AnchorPane prefHeight="400.0" prefWidth="600.0" xmlns="http://javafx.com/javafx/17" xmlns:fx="http://javafx.com/fxml/1" fx:controller="com.student.mathquiz.view.LoginViewController">
<VBox alignment="CENTER" layoutX="150.0" layoutY="50.0" prefHeight="300.0" prefWidth="300.0" spacing="20.0">
<Label text="用户登录"><font><Font size="24.0" /></font></Label>
<TextField fx:id="emailField" promptText="邮箱" />
<PasswordField fx:id="passwordField" promptText="密码" />
<Button onAction="#handleLogin" text="登录" />
<Button onAction="#handleGoToRegister" text="还没有账户?去注册" style="-fx-background-color: transparent; -fx-border-color: transparent; -fx-underline: true; -fx-cursor: hand;" />
<Label fx:id="statusLabel" textFill="RED" />
</VBox>
</AnchorPane>

@ -0,0 +1,37 @@
// LoginViewController.java
package com.student.mathquiz.view;
import com.student.mathquiz.MainApp;
import javafx.fxml.FXML;
import javafx.scene.control.Label;
import javafx.scene.control.PasswordField;
import javafx.scene.control.TextField;
public class LoginViewController {
@FXML private TextField emailField;
@FXML private PasswordField passwordField;
@FXML private Label statusLabel;
private MainApp mainApp;
public void setMainApp(MainApp mainApp) {
this.mainApp = mainApp;
}
@FXML
private void handleLogin() {
// TODO: 在这里调用后端 loginService.login(...)
if ("test".equals(emailField.getText()) && "123".equals(passwordField.getText())) {
// 登录成功,让 MainApp 切换到主菜单界面
mainApp.showMainMenuView();
} else {
statusLabel.setText("邮箱或密码错误!");
}
}
@FXML
private void handleGoToRegister() {
// 让 MainApp 切换到注册界面
mainApp.showRegisterView();
}
}

@ -0,0 +1,13 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- MainMenuView.fxml -->
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<?import javafx.scene.text.Font?>
<AnchorPane prefHeight="400.0" prefWidth="600.0" xmlns="http://javafx.com/javafx/17" xmlns:fx="http://javafx.com/fxml/1" fx:controller="com.student.mathquiz.view.MainMenuViewController">
<VBox alignment="CENTER" layoutX="200.0" layoutY="100.0" prefHeight="200.0" prefWidth="200.0" spacing="20.0">
<Label text="请选择难度"><font><Font size="24.0" /></font></Label>
<Button onAction="#handlePrimary" prefWidth="100.0" text="小学" />
<Button onAction="#handleMiddle" prefWidth="100.0" text="初中" />
<Button onAction="#handleHigh" prefWidth="100.0" text="高中" />
</VBox>
</AnchorPane>

@ -0,0 +1,32 @@
// MainMenuViewController.java
package com.student.mathquiz.view;
import com.student.mathquiz.MainApp;
import javafx.fxml.FXML;
public class MainMenuViewController {
private MainApp mainApp;
public void setMainApp(MainApp mainApp) {
this.mainApp = mainApp;
}
@FXML
private void handlePrimary() {
System.out.println("选择了小学难度");
// TODO: 调用 mainApp.showQuizView("小学");
mainApp.showQuizView();
}
@FXML
private void handleMiddle() {
System.out.println("选择了初中难度");
mainApp.showQuizView();
}
@FXML
private void handleHigh() {
System.out.println("选择了高中难度");
mainApp.showQuizView();
}
}

@ -0,0 +1,54 @@
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.geometry.Insets?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.control.RadioButton?>
<?import javafx.scene.control.ToggleGroup?>
<?import javafx.scene.layout.AnchorPane?>
<?import javafx.scene.layout.VBox?>
<?import javafx.scene.text.Font?>
<AnchorPane prefHeight="400.0" prefWidth="600.0" xmlns="http://javafx.com/javafx/17" xmlns:fx="http://javafx.com/fxml/1" fx:controller="com.student.mathquiz.view.QuizViewController">
<children>
<VBox alignment="TOP_CENTER" layoutX="50.0" layoutY="50.0" prefHeight="300.0" prefWidth="500.0" spacing="15.0">
<children>
<Label fx:id="questionNumberLabel" text="第 1/10 题">
<font>
<Font name="System Bold" size="18.0" />
</font>
</Label>
<Label fx:id="questionTextLabel" alignment="CENTER" text="这里是题干1 + 1 = ?" wrapText="true">
<font>
<Font size="20.0" />
</font>
<VBox.margin>
<Insets bottom="10.0" />
</VBox.margin>
</Label>
<!-- 选项部分 -->
<VBox fx:id="optionsBox" alignment="CENTER_LEFT" prefWidth="100.0" spacing="10.0">
<children>
<RadioButton fx:id="option1" mnemonicParsing="false" text="选项 A">
<toggleGroup>
<ToggleGroup fx:id="optionsGroup" />
</toggleGroup>
</RadioButton>
<RadioButton fx:id="option2" mnemonicParsing="false" text="选项 B" toggleGroup="$optionsGroup" />
<RadioButton fx:id="option3" mnemonicParsing="false" text="选项 C" toggleGroup="$optionsGroup" />
<RadioButton fx:id="option4" mnemonicParsing="false" text="选项 D" toggleGroup="$optionsGroup" />
</children>
<padding>
<Insets left="150.0" />
</padding>
</VBox>
<Button fx:id="submitButton" mnemonicParsing="false" onAction="#handleSubmitAnswer" text="提交/下一题" />
<Label fx:id="feedbackLabel" textFill="GREEN">
<font>
<Font name="System Bold" size="14.0" />
</font>
</Label>
</children>
</VBox>
</children>
</AnchorPane>

@ -0,0 +1,93 @@
package com.student.mathquiz.view;
import com.student.mathquiz.MainApp;
import javafx.fxml.FXML;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.RadioButton;
import javafx.scene.control.ToggleGroup;
public class QuizViewController {
@FXML private Label questionNumberLabel;
@FXML private Label questionTextLabel;
@FXML private RadioButton option1;
@FXML private RadioButton option2;
@FXML private RadioButton option3;
@FXML private RadioButton option4;
@FXML private ToggleGroup optionsGroup;
@FXML private Button submitButton;
@FXML private Label feedbackLabel;
private MainApp mainApp;
public void setMainApp(MainApp mainApp) {
this.mainApp = mainApp;
}
/**
* JavaFX FXML .
*/
@FXML
private void initialize() {
// 这里可以放一些初始化的代码
// 比如,加载第一道题
loadQuestion();
}
/**
* .
*
* Question
*/
private void loadQuestion() {
// --- 这是伪代码,用来给你展示效果 ---
questionNumberLabel.setText("第 1/10 题");
questionTextLabel.setText("1 + 1 = ?");
option1.setText("A. 1");
option2.setText("B. 2");
option3.setText("C. 3");
option4.setText("D. 4");
feedbackLabel.setText(""); // 清空上一题的反馈
if (optionsGroup.getSelectedToggle() != null) {
optionsGroup.getSelectedToggle().setSelected(false); // 取消上一题的选择
}
// --- 伪代码结束 ---
}
/**
* /.
*/
@FXML
private void handleSubmitAnswer() {
RadioButton selectedOption = (RadioButton) optionsGroup.getSelectedToggle();
if (selectedOption == null) {
feedbackLabel.setText("请选择一个答案!");
return;
}
// TODO: 在这里调用后端 quizService.checkAnswer(...) 来判断对错
// boolean isCorrect = quizService.checkAnswer(currentQuestion, selectedOption.getText());
// --- 这是伪代码,模拟判断对错 ---
if (selectedOption == option2) {
feedbackLabel.setText("回答正确!");
} else {
feedbackLabel.setText("回答错误!正确答案是 B");
}
// --- 伪代码结束 ---
// TODO: 在这里判断是不是最后一题
// if (quiz.isLastQuestion()) {
// mainApp.showScoreView(quiz.getScore());
// } else {
// loadQuestion(quiz.getNextQuestion());
// }
// 初版:我们先做一个假的跳转到分数界面
System.out.println("答题完成(伪)!跳转到分数界面...");
mainApp.showScoreView();
}
}

@ -0,0 +1,20 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- RegisterView.fxml -->
<?import javafx.geometry.Insets?>
<?import javafx.scene.control.*?>
<?import javafx.geometry.Insets?>
<?import javafx.scene.layout.*?>
<?import javafx.scene.text.Font?>
<AnchorPane prefHeight="400.0" prefWidth="600.0" xmlns="http://javafx.com/javafx/17" xmlns:fx="http://javafx.com/fxml/1" fx:controller="com.student.mathquiz.view.RegisterViewController">
<VBox alignment="CENTER" layoutX="150.0" layoutY="25.0" prefHeight="350.0" prefWidth="300.0" spacing="15.0">
<Label text="用户注册"><font><Font size="24.0" /></font></Label>
<TextField fx:id="emailField" promptText="邮箱" />
<Button onAction="#handleSendCode" text="发送验证码" />
<TextField fx:id="codeField" promptText="验证码" />
<PasswordField fx:id="passwordField1" promptText="设置密码 (6-10位,含大小写字母和数字)" />
<PasswordField fx:id="passwordField2" promptText="确认密码" />
<Button onAction="#handleRegister" text="注册" />
<Button onAction="#handleGoToLogin" text="已有账户?去登录" style="-fx-background-color: transparent; -fx-border-color: transparent; -fx-underline: true; -fx-cursor: hand;" />
<Label fx:id="statusLabel" textFill="RED" wrapText="true" />
</VBox>
</AnchorPane>

@ -0,0 +1,59 @@
// RegisterViewController.java
package com.student.mathquiz.view;
import com.student.mathquiz.MainApp;
import javafx.application.Platform;
import javafx.fxml.FXML;
import javafx.scene.control.Label;
import javafx.scene.control.TextField;
public class RegisterViewController {
public TextField codeField;
public TextField emailField;
@FXML private Label statusLabel;
private MainApp mainApp;
public void setMainApp(MainApp mainApp) {
this.mainApp = mainApp;
}
@FXML
private void handleSendCode() {
// TODO: 在这里调用后端 userService.sendVerificationCode(...)
String email = emailField.getText();
// TODO: 在这里先加一个邮箱格式校验
String code = EmailService.generateVerificationCode();
// ★★★ 在后台线程中发送邮件,防止界面卡死! ★★★
new Thread(() -> {
boolean success = EmailService.sendVerificationEmail(email, code);
// 在 JavaFX 主线程中更新界面
Platform.runLater(() -> {
if (success) {
statusLabel.setText("验证码已发送至您的邮箱,请查收!");
// TODO: 把 code 和 email 存起来,用于稍后的验证
} else {
statusLabel.setText("验证码发送失败,请检查邮箱地址或网络!");
}
});
}).start();
}
@FXML
private void handleRegister() {
// TODO: 在这里进行输入校验,并调用后端 userService.register(...)
statusLabel.setText("注册成功(伪)!请登录。");
mainApp.showLoginView();
}
@FXML
private void handleGoToLogin() {
mainApp.showLoginView();
}
}
// 在 RegisterViewController.java 里

@ -0,0 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.layout.BorderPane?>
<BorderPane xmlns="http://javafx.com/javafx/8.0.171" xmlns:fx="http://javafx.com/fxml/1" />

@ -0,0 +1,28 @@
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.layout.AnchorPane?>
<?import javafx.scene.layout.VBox?>
<?import javafx.scene.text.Font?>
<AnchorPane prefHeight="400.0" prefWidth="600.0" xmlns="http://javafx.com/javafx/17" xmlns:fx="http://javafx.com/fxml/1" fx:controller="com.student.mathquiz.view.ScoreViewController">
<children>
<VBox alignment="CENTER" layoutX="200.0" layoutY="100.0" prefHeight="200.0" prefWidth="200.0" spacing="20.0">
<children>
<Label text="测试完成!">
<font>
<Font name="System Bold" size="24.0" />
</font>
</Label>
<Label fx:id="scoreLabel" text="你的分数是: 100">
<font>
<Font size="18.0" />
</font>
</Label>
<Button onAction="#handleTryAgain" text="再做一组" />
<Button onAction="#handleExit" text="退出程序" />
</children>
</VBox>
</children>
</AnchorPane>

@ -0,0 +1,38 @@
package com.student.mathquiz.view;
import com.student.mathquiz.MainApp;
import javafx.application.Platform;
import javafx.fxml.FXML;
import javafx.scene.control.Label;
public class ScoreViewController {
@FXML
private Label scoreLabel;
private MainApp mainApp;
public void setMainApp(MainApp mainApp) {
this.mainApp = mainApp;
}
/**
* MainApp .
* @param score
*/
public void setScore(int score) {
scoreLabel.setText("你的分数是: " + score);
}
@FXML
private void handleTryAgain() {
// 返回主菜单,让用户可以重新选择难度
mainApp.showMainMenuView();
}
@FXML
private void handleExit() {
// 退出整个应用程序
Platform.exit();
}
}

@ -1,29 +0,0 @@
package persistence;
import question.Question;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.List;
public class FileSaver {
public static void saveQuestions(String username, List<Question> questions) {
File dir = new File(username);
if (!dir.exists()) dir.mkdirs();
String filename = LocalDateTime.now().format(
DateTimeFormatter.ofPattern("yyyy-MM-dd-HH-mm-ss")) + ".txt";
try (FileWriter writer = new FileWriter(new File(dir, filename))) {
for (int i = 0; i < questions.size(); i++) {
writer.write((i + 1) + ". " + questions.get(i).getQuestion() + "\n\n");
}
} catch (IOException e) {
e.printStackTrace();
}
System.out.println("题目已生成并保存!");
}
}

@ -1,43 +0,0 @@
package persistence;
import java.io.File;
import java.io.FileNotFoundException;
import java.util.Scanner;
public class QuestionChecker {
public static boolean isDuplicate(String username, String question) {
File dir = new File(username);
if (!dir.exists()) return false;
File[] files = dir.listFiles();/*每次调用都获取一次文件列表*/
if (files == null) return false;
// 待查题目去掉空格,方便精确匹配
String target = question.trim();
for (File file : files) {/* 遍历所有历史文件 */
if (file.isFile() && file.getName().endsWith(".txt")) {
try (Scanner scanner = new Scanner(file)) {
while (scanner.hasNextLine()) {
String line = scanner.nextLine().trim(); /*遍历文件中的每一行 */
if (line.isEmpty()) continue;// 跳过空行
// 去掉题号部分(如 "1. "
int dotIndex = line.indexOf('.');
if (dotIndex != -1) {
String storedQuestion = line.substring(dotIndex + 1).trim();
// 精确匹配
if (storedQuestion.equals(target)) {
return true;
}
}
}
} catch (FileNotFoundException e) {
e.printStackTrace();
}
}
}
return false;
}
}

@ -1,26 +0,0 @@
package question;
import java.util.Random;
public class HighQuestionGenerator implements QuestionGenerator {
private static final Random random = new Random();
private final QuestionGenerator primaryGenerator = new PrimaryQuestionGenerator();
@Override
public Question generateQuestion() {
Question q = primaryGenerator.generateQuestion();
String[] funcs = {"sin", "cos", "tan"};
String func = funcs[random.nextInt(funcs.length)];
return new Question(func + "(" + q.getQuestion() + ")", evaluate(func, q.getQuestion()));
}
private String evaluate(String func, String expr) {
try {
javax.script.ScriptEngineManager mgr = new javax.script.ScriptEngineManager();
javax.script.ScriptEngine engine = mgr.getEngineByName("JavaScript");
return String.valueOf(engine.eval("Math." + func + "(Math.toRadians(" + expr + "))"));
} catch (Exception e) {
return "?";
}
}
}

@ -1,28 +0,0 @@
package question;
import java.util.Random;
public class MiddleQuestionGenerator implements QuestionGenerator {
private static final Random random = new Random();
private final QuestionGenerator primaryGenerator = new PrimaryQuestionGenerator();
@Override
public Question generateQuestion() {
Question q = primaryGenerator.generateQuestion();
if (random.nextBoolean()) {
return new Question(q.getQuestion() + " ^ 2", evaluate(q.getQuestion() + "^2"));
} else {
return new Question("√" + q.getQuestion(), evaluate("Math.sqrt(" + q.getQuestion() + ")"));
}
}
private String evaluate(String expr) {
try {
javax.script.ScriptEngineManager mgr = new javax.script.ScriptEngineManager();
javax.script.ScriptEngine engine = mgr.getEngineByName("JavaScript");
return String.valueOf(engine.eval(expr.replace("^", "**")));
} catch (Exception e) {
return "?";
}
}
}

@ -1,65 +0,0 @@
package question;
import java.util.Random;
public class PrimaryQuestionGenerator implements QuestionGenerator {
private static final Random random = new Random();
@Override
public Question generateQuestion() {
int numOperands = random.nextInt(5) + 1;
StringBuilder sb = new StringBuilder();
int currentValue = random.nextInt(100) + 1;
sb.append(currentValue);
for (int i = 1; i < numOperands; i++) {
String[] ops = {"+", "-", "*", "/"};
String op;
int nextVal;
do {
op = ops[random.nextInt(ops.length)];
nextVal = random.nextInt(100) + 1;
} while ((op.equals("-") && currentValue < nextVal) ||
(op.equals("/") && (nextVal == 0 || currentValue % nextVal != 0)));
sb.append(" ").append(op).append(" ").append(nextVal);
switch (op) {
case "+": currentValue += nextVal; break;
case "-": currentValue -= nextVal; break;
case "*": currentValue *= nextVal; break;
case "/": currentValue /= nextVal; break;
}
}
String expr = addParentheses(sb.toString());
return new Question(expr, evaluate(expr));
}
private String addParentheses(String expr) {
String[] tokens = expr.split(" ");
if (tokens.length < 3) return expr;
int start = random.nextInt(tokens.length / 2) * 2;
int end = start + 2 + random.nextInt((tokens.length - start) / 2) * 2;
end = Math.min(end, tokens.length - 1);
StringBuilder newExpr = new StringBuilder();
for (int i = 0; i < tokens.length; i++) {
if (i == start) newExpr.append("(");
newExpr.append(tokens[i]);
if (i == end) newExpr.append(")");
if (i != tokens.length - 1) newExpr.append(" ");
}
return newExpr.toString();
}
private String evaluate(String expr) {
try {
javax.script.ScriptEngineManager mgr = new javax.script.ScriptEngineManager();
javax.script.ScriptEngine engine = mgr.getEngineByName("JavaScript");
return String.valueOf(engine.eval(expr));
} catch (Exception e) {
return "?";
}
}
}

@ -1,20 +0,0 @@
package question;
public class Question {
private String question;
private String answer;
public Question(String question, String answer) {
this.question = question;
this.answer = answer;
}
public String getQuestion() {
return question;
}
public String getAnswer() {
return answer;
}
}

@ -1,5 +0,0 @@
package question;
public interface QuestionGenerator {
Question generateQuestion();
}
Loading…
Cancel
Save