稳定版本-美化界面版本

wanglirong_branch
hnu202326010328 6 months ago committed by hnu202326010318
parent 7faebe8f62
commit a4e93d42f6

@ -11,10 +11,14 @@ public class MainApplication extends Application {
@Override
public void start(Stage primaryStage) throws IOException {
// 启动时加载登录界面
Parent root = FXMLLoader.load(getClass().getResource("/com/mathgenerator/view/LoginView.fxml"));
Scene scene = new Scene(root);
// 确保样式表被加载
scene.getStylesheets().add(getClass().getResource("/com/mathgenerator/styles/styles.css").toExternalForm());
primaryStage.setTitle("中小学数学学习软件");
primaryStage.setScene(new Scene(root));
primaryStage.setScene(scene);
primaryStage.setResizable(false);
primaryStage.show();
}

@ -50,12 +50,6 @@ public class ChangePasswordController {
return;
}
// --- 新增的校验逻辑 ---
if (oldPassword.equals(newPassword)) {
showStatusMessage("新密码不能与当前密码相同!", true);
return;
}
if (!UserService.isPasswordValid(newPassword)) {
showStatusMessage("新密码格式错误必须为6-10位且包含大小写字母和数字。", true);
return;

@ -1,8 +1,6 @@
package com.mathgenerator.controller;
import com.mathgenerator.service.UserService;
import javafx.animation.KeyFrame;
import javafx.animation.Timeline;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
@ -13,8 +11,6 @@ import javafx.scene.control.Label;
import javafx.scene.control.PasswordField;
import javafx.scene.control.TextField;
import javafx.stage.Stage;
import javafx.util.Duration;
import java.io.IOException;
import com.mathgenerator.util.ValidationUtils;
@ -22,8 +18,6 @@ public class RegisterController {
private final UserService userService = new UserService();
private String sentCode; // 用于存储已发送的验证码
private Timeline countdownTimeline; // 新增用于倒计时的Timeline
private int countdownSeconds = 60; // 新增:倒计时总秒数
@FXML private TextField usernameField;
@FXML private TextField emailField;
@ -49,32 +43,12 @@ public class RegisterController {
// 处理发送结果
if (this.sentCode != null) {
showStatusMessage("验证码已成功发送,请查收您的邮箱。", true);
startCountdown(); // **核心修改:启动倒计时**
sendCodeButton.setDisable(true); // 防止重复点击
} else {
showStatusMessage("验证码发送失败!请检查配置或联系管理员。", true);
}
}
/**
* 60
*/
private void startCountdown() {
sendCodeButton.setDisable(true);
countdownTimeline = new Timeline(new KeyFrame(Duration.seconds(1), e -> {
countdownSeconds--;
sendCodeButton.setText(countdownSeconds + "s后重试");
if (countdownSeconds <= 0) {
countdownTimeline.stop();
sendCodeButton.setDisable(false);
sendCodeButton.setText("发送验证码");
countdownSeconds = 60; // 重置倒计时
}
}));
countdownTimeline.setCycleCount(60);
countdownTimeline.play();
}
@FXML
private void handleRegisterAction(ActionEvent event) {
// 1. 字段校验 (已简化,不再校验密码)

@ -40,11 +40,12 @@ public class SetPasswordController {
String confirmPassword = confirmPasswordField.getText();
if (!newPassword.equals(confirmPassword)) {
statusLabel.setText("两次输入的密码不匹配!");
showStatusMessage("两次输入的密码不匹配!", true);
return;
}
if (!ValidationUtils.isPasswordValid(newPassword)) {
statusLabel.setText("新密码格式错误必须为6-10位且包含大小写字母和数字。");
showStatusMessage("新密码格式错误必须为6-10位且包含大小写字母和数字。", true);
return;
}
@ -52,11 +53,39 @@ public class SetPasswordController {
boolean success = userService.setPassword(this.username, newPassword);
if (success) {
statusLabel.setText("密码设置成功!正在进入主菜单...");
showStatusMessage("密码设置成功!正在进入主菜单...", true);
// 密码设置成功后,获取完整的用户信息并直接跳转到主菜单
userService.findUserByUsername(this.username).ifPresent(this::loadMainMenu);
} else {
statusLabel.setText("密码设置失败,请稍后重试或重新注册。");
showStatusMessage("密码设置失败,请稍后重试或重新注册。", true);
}
}
/**
*
*/
private void showStatusMessage(String message, boolean hasContent) {
statusLabel.setText(message);
updateStatusLabelStyle(hasContent);
}
/**
*
* @param hasContent
*/
private void updateStatusLabelStyle(boolean hasContent) {
if (hasContent) {
// 移除空样式,添加有内容样式
statusLabel.getStyleClass().removeAll("setpassword-status-label");
if (!statusLabel.getStyleClass().contains("setpassword-status-label-with-text")) {
statusLabel.getStyleClass().add("setpassword-status-label-with-text");
}
} else {
// 移除有内容样式,添加空样式
statusLabel.getStyleClass().removeAll("setpassword-status-label-with-text");
if (!statusLabel.getStyleClass().contains("setpassword-status-label")) {
statusLabel.getStyleClass().add("setpassword-status-label");
}
}
}

@ -228,10 +228,10 @@
-fx-effect: dropshadow(gaussian, rgba(186, 104, 200, 0.5), 8, 0.4, 2, 2);
}
/* ===== 注册界面状态标签样式 - 修复版本 ===== */
/* ===== 注册界面状态标签样式 - 修复长句子版本 ===== */
.register-status-label {
-fx-text-fill: transparent;
-fx-font-size: 13px;
-fx-font-size: 12px;
-fx-font-weight: bold;
-fx-wrap-text: true;
-fx-background-color: transparent;
@ -244,27 +244,30 @@
-fx-text-alignment: center;
-fx-min-height: 0px;
-fx-pref-height: 0px;
-fx-max-width: 300px;
-fx-max-width: 280px;
-fx-line-spacing: 2px;
}
.register-status-label-with-text {
-fx-text-fill: #7b1fa2;
-fx-font-size: 13px;
-fx-font-size: 12px;
-fx-font-weight: bold;
-fx-wrap-text: true;
-fx-background-color: rgba(186, 104, 200, 0.15);
-fx-background-radius: 8px;
-fx-padding: 10px 15px;
-fx-background-radius: 10px;
-fx-padding: 12px 15px;
-fx-border-color: rgba(186, 104, 200, 0.3);
-fx-border-radius: 8px;
-fx-border-radius: 10px;
-fx-border-width: 1px;
-fx-alignment: center;
-fx-text-alignment: center;
-fx-min-height: 50px;
-fx-pref-height: 50px;
-fx-max-width: 300px;
-fx-min-height: 70px;
-fx-pref-height: 70px;
-fx-max-width: 280px;
-fx-line-spacing: 2px;
-fx-effect: dropshadow(gaussian, rgba(186, 104, 200, 0.2), 6, 0.3, 2, 2);
}
/* ===== 主菜单界面专用样式 - 浅紫色为主,浅黄色为辅 ===== */
.mainmenu-background-new {
-fx-background-image: url('file:src/main/resources/com/mathgenerator/images/mainmenu-bg.png');
@ -283,11 +286,16 @@
-fx-effect: dropshadow(gaussian, rgba(156, 39, 176, 0.25), 25, 0.5, 0, 8);
}
/* ===== 主菜单欢迎标题样式 - 修复长用户名显示 ===== */
.mainmenu-welcome-title {
-fx-text-fill: #7b1fa2;
-fx-font-weight: bold;
-fx-font-size: 28px;
-fx-effect: dropshadow(gaussian, rgba(123, 31, 162, 0.3), 4, 0.6, 2, 2);
-fx-font-size: 24px;
-fx-effect: dropshadow(gaussian, rgba(123, 31, 162, 0.25), 4, 0.6, 2, 2);
-fx-wrap-text: true;
-fx-text-alignment: center;
-fx-alignment: center;
-fx-max-width: 360px;
}
.mainmenu-difficulty-label {
@ -821,3 +829,120 @@
-fx-max-width: 300px;
-fx-effect: dropshadow(gaussian, rgba(186, 104, 200, 0.2), 6, 0.3, 2, 2);
}
/* ===== 设置密码界面专用样式 - 淡黄色和淡紫色主题 ===== */
.setpassword-background {
-fx-background-image: url('file:src/main/resources/com/mathgenerator/images/background.png');
-fx-background-size: cover;
-fx-background-position: center center;
-fx-background-repeat: no-repeat;
-fx-background-color: linear-gradient(to bottom right, #fff9c4, #f3e5f5);
}
.setpassword-glass-panel {
-fx-background-color: rgba(255, 255, 255, 0.88);
-fx-background-radius: 30px;
-fx-border-radius: 30px;
-fx-border-color: rgba(186, 104, 200, 0.4);
-fx-border-width: 2px;
-fx-effect: dropshadow(gaussian, rgba(156, 39, 176, 0.2), 25, 0.5, 0, 8);
}
.setpassword-title {
-fx-text-fill: #7b1fa2;
-fx-font-weight: bold;
-fx-font-size: 26px;
-fx-effect: dropshadow(gaussian, rgba(123, 31, 162, 0.25), 4, 0.6, 2, 2);
}
.setpassword-prompt {
-fx-text-fill: #7b1fa2;
-fx-font-size: 14px;
-fx-font-weight: bold;
-fx-wrap-text: true;
-fx-background-color: rgba(186, 104, 200, 0.1);
-fx-background-radius: 10px;
-fx-padding: 10px 15px;
-fx-border-color: rgba(186, 104, 200, 0.2);
-fx-border-radius: 10px;
-fx-border-width: 1px;
-fx-alignment: center;
}
.setpassword-textfield {
-fx-background-color: rgba(255, 255, 255, 0.95);
-fx-border-color: rgba(186, 104, 200, 0.5);
-fx-border-radius: 15px;
-fx-background-radius: 15px;
-fx-padding: 12px 16px;
-fx-font-size: 14px;
-fx-effect: dropshadow(gaussian, rgba(186, 104, 200, 0.2), 6, 0.2, 2, 2);
}
.setpassword-textfield:focused {
-fx-border-color: rgba(156, 39, 176, 0.8);
-fx-border-width: 2px;
-fx-effect: dropshadow(gaussian, rgba(156, 39, 176, 0.3), 8, 0.3, 2, 2);
}
.setpassword-primary-button {
-fx-background-color: linear-gradient(to bottom, #ba68c8, #ab47bc);
-fx-text-fill: white;
-fx-font-size: 16px;
-fx-font-weight: bold;
-fx-background-radius: 25px;
-fx-border-radius: 25px;
-fx-border-color: #ab47bc;
-fx-border-width: 2px;
-fx-padding: 12px 24px;
-fx-min-width: 150px;
-fx-cursor: hand;
-fx-effect: dropshadow(gaussian, rgba(186, 104, 200, 0.4), 8, 0.3, 2, 2);
}
.setpassword-primary-button:hover {
-fx-background-color: linear-gradient(to bottom, #ce93d8, #ba68c8);
-fx-effect: dropshadow(gaussian, rgba(186, 104, 200, 0.6), 10, 0.4, 3, 3);
-fx-scale-x: 1.05;
-fx-scale-y: 1.05;
}
/* ===== 设置密码界面状态标签样式 - 修复页面滑动 ===== */
.setpassword-status-label {
-fx-text-fill: transparent;
-fx-font-size: 12px;
-fx-font-weight: bold;
-fx-wrap-text: true;
-fx-background-color: transparent;
-fx-background-radius: 10px;
-fx-padding: 0px;
-fx-border-color: transparent;
-fx-border-radius: 10px;
-fx-border-width: 0px;
-fx-alignment: center;
-fx-text-alignment: center;
-fx-min-height: 70px;
-fx-pref-height: 70px;
-fx-max-width: 280px;
-fx-line-spacing: 2px;
}
.setpassword-status-label-with-text {
-fx-text-fill: #7b1fa2;
-fx-font-size: 12px;
-fx-font-weight: bold;
-fx-wrap-text: true;
-fx-background-color: rgba(186, 104, 200, 0.15);
-fx-background-radius: 10px;
-fx-padding: 12px 15px;
-fx-border-color: rgba(186, 104, 200, 0.3);
-fx-border-radius: 10px;
-fx-border-width: 1px;
-fx-alignment: center;
-fx-text-alignment: center;
-fx-min-height: 70px;
-fx-pref-height: 70px;
-fx-max-width: 280px;
-fx-line-spacing: 2px;
-fx-effect: dropshadow(gaussian, rgba(186, 104, 200, 0.2), 6, 0.3, 2, 2);
}

@ -10,29 +10,30 @@
<VBox alignment="TOP_CENTER" maxHeight="-Infinity" maxWidth="-Infinity"
minHeight="-Infinity" minWidth="-Infinity" prefHeight="700.0"
prefWidth="400.0" spacing="25.0" styleClass="mainmenu-background-new, root-container"
prefWidth="400.0" spacing="20.0" styleClass="mainmenu-background-new, root-container"
xmlns="http://javafx.com/javafx/17"
xmlns:fx="http://javafx.com/fxml/1"
fx:controller="com.mathgenerator.controller.MainMenuController"
stylesheets="@/com/mathgenerator/styles/styles.css">
<padding>
<Insets bottom="30.0" left="30.0" right="30.0" top="30.0" />
<Insets bottom="25.0" left="25.0" right="25.0" top="25.0" />
</padding>
<children>
<!-- 欢迎标题 -->
<Label fx:id="welcomeLabel" text="欢迎, [用户名]!" styleClass="mainmenu-welcome-title">
<!-- 欢迎标题 - 修复长用户名显示 -->
<Label fx:id="welcomeLabel" text="欢迎, [用户名]!" styleClass="mainmenu-welcome-title"
maxWidth="360.0" alignment="CENTER" wrapText="true">
<font>
<Font name="System Bold" size="28.0" />
<Font name="System Bold" size="24.0" />
</font>
<VBox.margin>
<Insets bottom="20.0" />
<Insets bottom="15.0" />
</VBox.margin>
</Label>
<!-- 主要内容区域 -->
<VBox alignment="CENTER" spacing="25.0" VBox.vgrow="ALWAYS"
<VBox alignment="CENTER" spacing="20.0" VBox.vgrow="ALWAYS"
styleClass="mainmenu-glass-panel" prefWidth="340.0">
<children>
<!-- 难度选择标签 -->
@ -41,7 +42,7 @@
<Font size="20.0" />
</font>
<VBox.margin>
<Insets bottom="15.0" />
<Insets bottom="12.0" />
</VBox.margin>
</Label>
@ -57,47 +58,47 @@
</HBox>
</children>
<VBox.margin>
<Insets bottom="15.0" />
<Insets bottom="12.0" />
</VBox.margin>
</VBox>
<!-- 难度选择按钮 -->
<VBox alignment="CENTER" spacing="18.0">
<VBox alignment="CENTER" spacing="15.0">
<children>
<Button fx:id="primaryButton" mnemonicParsing="false"
onAction="#handlePrimaryAction" prefHeight="60.0"
prefWidth="220.0" text="小学" styleClass="mainmenu-difficulty-button" />
onAction="#handlePrimaryAction" prefHeight="55.0"
prefWidth="200.0" text="小学" styleClass="mainmenu-difficulty-button" />
<Button fx:id="juniorHighButton" mnemonicParsing="false"
onAction="#handleJuniorHighAction" prefHeight="60.0"
prefWidth="220.0" text="初中" styleClass="mainmenu-difficulty-button" />
onAction="#handleJuniorHighAction" prefHeight="55.0"
prefWidth="200.0" text="初中" styleClass="mainmenu-difficulty-button" />
<Button fx:id="seniorHighButton" mnemonicParsing="false"
onAction="#handleSeniorHighAction" prefHeight="60.0"
prefWidth="220.0" text="高中" styleClass="mainmenu-difficulty-button" />
onAction="#handleSeniorHighAction" prefHeight="55.0"
prefWidth="200.0" text="高中" styleClass="mainmenu-difficulty-button" />
</children>
</VBox>
<!-- 状态标签 -->
<Label fx:id="statusLabel" styleClass="mainmenu-status-label"
maxWidth="300.0" alignment="CENTER" text="" />
maxWidth="280.0" alignment="CENTER" text="" />
</children>
<padding>
<Insets bottom="30.0" left="25.0" right="25.0" top="25.0" />
<Insets bottom="25.0" left="20.0" right="20.0" top="20.0" />
</padding>
</VBox>
<!-- 底部功能按钮 -->
<HBox alignment="CENTER" spacing="15.0" prefHeight="70.0">
<HBox alignment="CENTER" spacing="12.0" prefHeight="60.0">
<children>
<Button fx:id="changePasswordButton" mnemonicParsing="false"
onAction="#handleChangePasswordAction" prefWidth="140.0"
onAction="#handleChangePasswordAction"
text="修改密码" styleClass="mainmenu-function-button" />
<Button fx:id="logoutButton" mnemonicParsing="false"
onAction="#handleLogoutAction" prefWidth="140.0"
onAction="#handleLogoutAction"
text="退出登录" styleClass="mainmenu-logout-button" />
</children>
<VBox.margin>
<Insets top="25.0" bottom="10.0" />
<Insets top="20.0" bottom="5.0" />
</VBox.margin>
</HBox>
</children>

@ -76,13 +76,13 @@
</VBox.margin>
</VBox>
<!-- 状态标签 - 使用空样式 -->
<!-- 状态标签 - 增加高度以显示长句子 -->
<Label fx:id="statusLabel" styleClass="register-status-label"
maxWidth="300.0" alignment="CENTER" text=""
maxWidth="280.0" alignment="CENTER" text=""
wrapText="true"
minHeight="50.0" prefHeight="50.0">
minHeight="70.0" prefHeight="70.0">
<VBox.margin>
<Insets top="10.0" />
<Insets top="8.0" />
</VBox.margin>
</Label>
</children>

@ -9,63 +9,65 @@
<VBox alignment="CENTER" maxHeight="-Infinity" maxWidth="-Infinity"
minHeight="-Infinity" minWidth="-Infinity" prefHeight="700.0"
prefWidth="400.0" spacing="20.0" styleClass="background-container, root-container"
prefWidth="400.0" spacing="15.0" styleClass="setpassword-background, root-container"
xmlns="http://javafx.com/javafx/17"
xmlns:fx="http://javafx.com/fxml/1"
fx:controller="com.mathgenerator.controller.SetPasswordController"
stylesheets="@/com/mathgenerator/styles/styles.css">
<children>
<VBox alignment="CENTER" spacing="20.0" styleClass="glass-panel-very-light"
prefWidth="360.0" prefHeight="400.0">
<VBox alignment="CENTER" spacing="15.0" styleClass="setpassword-glass-panel"
prefWidth="360.0" prefHeight="480.0">
<children>
<!-- 标题 -->
<Label text="设置初始密码" styleClass="title-label">
<Label text="设置初始密码" styleClass="setpassword-title">
<font>
<Font name="System Bold" size="26.0" />
</font>
<VBox.margin>
<Insets bottom="10.0" />
<Insets bottom="5.0" />
</VBox.margin>
</Label>
<!-- 提示信息 -->
<Label fx:id="promptLabel" text="为您的账户 [用户名] 设置密码"
styleClass="security-tip" maxWidth="320.0" alignment="CENTER" />
styleClass="setpassword-prompt" maxWidth="280.0" alignment="CENTER" wrapText="true" />
<!-- 新密码 -->
<PasswordField fx:id="newPasswordField" maxWidth="320.0"
<PasswordField fx:id="newPasswordField" maxWidth="280.0"
promptText="新密码 (6-10位, 含大小写字母和数字)"
styleClass="glass-textfield" />
styleClass="setpassword-textfield" />
<!-- 确认密码 -->
<PasswordField fx:id="confirmPasswordField" maxWidth="320.0"
promptText="确认新密码" styleClass="glass-textfield" />
<PasswordField fx:id="confirmPasswordField" maxWidth="280.0"
promptText="确认新密码" styleClass="setpassword-textfield" />
<!-- 确认按钮 -->
<Button fx:id="confirmButton" mnemonicParsing="false"
onAction="#handleConfirmAction" prefWidth="150.0"
text="确认并进入" styleClass="primary-button-light" />
onAction="#handleConfirmAction"
text="确认并进入" styleClass="setpassword-primary-button" />
<!-- 状态标签 -->
<Label fx:id="statusLabel" styleClass="change-password-status"
maxWidth="320.0" alignment="CENTER" text=" ">
<!-- 状态标签 - 预留固定空间,防止页面滑动 -->
<Label fx:id="statusLabel" styleClass="setpassword-status-label"
maxWidth="280.0" alignment="CENTER" text=""
wrapText="true"
minHeight="70.0" prefHeight="70.0" maxHeight="70.0">
<VBox.margin>
<Insets top="15.0" />
<Insets top="8.0" />
</VBox.margin>
</Label>
</children>
<!-- 卡片内边距 -->
<padding>
<Insets bottom="35.0" left="35.0" right="35.0" top="35.0" />
<Insets bottom="25.0" left="30.0" right="30.0" top="25.0" />
</padding>
</VBox>
</children>
<!-- 主容器内边距 -->
<padding>
<Insets bottom="30.0" left="30.0" right="30.0" top="30.0" />
<Insets bottom="20.0" left="20.0" right="20.0" top="20.0" />
</padding>
</VBox>
Loading…
Cancel
Save