From e4761d34e0928c95a1dad633e016f160b177caca Mon Sep 17 00:00:00 2001 From: tzdwindows 7 <3076584115@qq.com> Date: Tue, 12 Aug 2025 21:22:24 +0800 Subject: [PATCH] =?UTF-8?q?feat(gui):=20=E9=87=8D=E6=9E=84=E7=99=BB?= =?UTF-8?q?=E5=BD=95=E7=95=8C=E9=9D=A2=E4=B8=BA=E7=8E=B0=E4=BB=A3=E5=8D=95?= =?UTF-8?q?=E7=AA=97=E5=8F=A3=E5=B8=83=E5=B1=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 设计并实现单窗口多视图的登录/注册/找回密码界面- 添加平滑的视图切换动画效果 - 优化输入框和按钮的样式,提升用户体验- 重构部分验证逻辑,提高代码可读性 --- .../axis/innovators/box/gui/LoginWindow.java | 864 ++++++++++-------- .../box/verification/OnlineVerification.java | 23 +- .../innovators/box/verification/UserTags.java | 5 + .../box/verification/VerificationService.java | 13 + state/toolbox.properties | 4 - 5 files changed, 513 insertions(+), 396 deletions(-) delete mode 100644 state/toolbox.properties diff --git a/src/main/java/com/axis/innovators/box/gui/LoginWindow.java b/src/main/java/com/axis/innovators/box/gui/LoginWindow.java index 43f602c..3b50b53 100644 --- a/src/main/java/com/axis/innovators/box/gui/LoginWindow.java +++ b/src/main/java/com/axis/innovators/box/gui/LoginWindow.java @@ -7,29 +7,41 @@ import com.formdev.flatlaf.FlatDarculaLaf; import javax.swing.*; import javax.swing.border.LineBorder; +import javax.swing.text.JTextComponent; import java.awt.*; +import java.awt.event.ActionEvent; import java.lang.reflect.InvocationTargetException; import java.util.concurrent.atomic.AtomicReference; /** - * 用于登录的主窗口 - * @author tzdwindows 7 + * 重构后的现代化单窗口登录/注册/找回密码界面(带平滑切换动画) + * 保留原有验证逻辑接口调用(OnlineVerification / VerificationService) + * + * 说明: + * - 单窗口(JDialog)内使用滑动动画切换视图(仿微软登录体验)。 + * - 所有子界面(登录/注册/找回密码)都在同一容器中切换,不再弹新窗口。 + * - 按钮与输入框固定宽度,避免被挤压变形。 + * + * 注意:需要 flatlaf 依赖以呈现更现代的外观。 */ public class LoginWindow { private static final AtomicReference loginResult = new AtomicReference<>(UserTags.None); - private JDialog dialog; - private JTextField emailField; - private JPasswordField passwordField; - private JCheckBox showPasswordCheckBox; - private static final int FIELD_WIDTH = 300; - private static final int FIELD_HEIGHT = 35; + + private final JDialog dialog; + private final JLayeredPane layeredPane; + private final int DIALOG_WIDTH = 460; + private final int DIALOG_HEIGHT = 560; + + // 登录面板中的控件需要在类域以便访问 + private JTextField loginEmailField; + private JPasswordField loginPasswordField; + public static UserTags createAndShow() throws InterruptedException, InvocationTargetException { AtomicReference result = new AtomicReference<>(UserTags.None); SwingUtilities.invokeAndWait(() -> { - LoginWindow loginWindow = new LoginWindow(); - loginWindow.dialog.setVisible(true); + LoginWindow window = new LoginWindow(); + window.dialog.setVisible(true); result.set(loginResult.get()); - if (result.get() == UserTags.None) { System.exit(0); } @@ -37,171 +49,476 @@ public class LoginWindow { return result.get(); } - private LoginWindow() { + public LoginWindow() { setupLookAndFeel(); - createMainDialog(); - buildLoginUI(); + dialog = new JDialog((Frame) null, "AXIS 安全认证", true); + dialog.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE); + dialog.setSize(DIALOG_WIDTH, DIALOG_HEIGHT); + dialog.setResizable(false); + dialog.setLocationRelativeTo(null); + + // 根容器:深色背景并居中卡片 + JPanel root = new JPanel(new GridBagLayout()); + root.setBackground(new Color(0x202225)); + root.setBorder(BorderFactory.createEmptyBorder(20, 20, 20, 20)); + dialog.setContentPane(root); + + // 卡片容器(居中) + JPanel cardWrapper = new JPanel(null) { + @Override + public Dimension getPreferredSize() { + return new Dimension(DIALOG_WIDTH - 40, DIALOG_HEIGHT - 40); + } + }; + cardWrapper.setOpaque(false); + cardWrapper.setPreferredSize(new Dimension(DIALOG_WIDTH - 40, DIALOG_HEIGHT - 40)); + + GridBagConstraints gbc = new GridBagConstraints(); + gbc.gridx = 0; + gbc.gridy = 0; + root.add(cardWrapper, gbc); + + // 分层面板用于动画 + layeredPane = new JLayeredPane(); + layeredPane.setBounds(0, 0, DIALOG_WIDTH - 40, DIALOG_HEIGHT - 40); + cardWrapper.add(layeredPane); + + // 卡片背景(圆角) + JPanel backgroundCard = new JPanel(); + backgroundCard.setBackground(new Color(0x2A2E31)); + backgroundCard.setBorder(new RoundBorder(16, new Color(0x3A3F42))); + backgroundCard.setBounds(0, 0, layeredPane.getWidth(), layeredPane.getHeight()); + backgroundCard.setLayout(null); + layeredPane.add(backgroundCard, Integer.valueOf(0)); + + // 创建三个面板(宽度等于容器宽度),初始将登录面板放置在0位置 + JPanel loginPanel = buildLoginPanel(); + JPanel registerPanel = buildRegisterPanel(); + JPanel forgotPanel = buildForgotPanel(); + + int w = layeredPane.getWidth(); + int h = layeredPane.getHeight(); + + loginPanel.setBounds(0, 0, w, h); + registerPanel.setBounds(w, 0, w, h); // 右侧预置 + forgotPanel.setBounds(w * 2, 0, w, h); + + layeredPane.add(loginPanel, Integer.valueOf(1)); + layeredPane.add(registerPanel, Integer.valueOf(1)); + layeredPane.add(forgotPanel, Integer.valueOf(1)); + + dialog.pack(); + // ensure layered sizes match after pack + SwingUtilities.invokeLater(() -> { + layeredPane.setBounds(0, 0, cardWrapper.getWidth(), cardWrapper.getHeight()); + backgroundCard.setBounds(0, 0, layeredPane.getWidth(), layeredPane.getHeight()); + int nw = layeredPane.getWidth(), nh = layeredPane.getHeight(); + loginPanel.setBounds(0, 0, nw, nh); + registerPanel.setBounds(nw, 0, nw, nh); + forgotPanel.setBounds(nw * 2, 0, nw, nh); + }); + } + + // 切换动画:direction = 1 表示向左滑动进入下一页(当前 -> 右侧),-1 表示向右滑动进入上一页 + private void slideTo(int targetIndex) { + Component[] comps = layeredPane.getComponents(); + // 每个面板宽度 + int w = layeredPane.getWidth(); + // 当前最左边的x位置(找到最左的那个主要面板) + // 我们采用简单方式:目标面板应该位于 x = targetIndex * w (0,1,2) + int targetX = -targetIndex * w; // 我们会将所有面板整体平移,使目标显示在 x=0 + + // 获取当前 offset (使用第一个面板的 x 来代表整体偏移) + int startOffset = 0; + // find current offset by checking bounds of first panel (assume index 0 is login) + if (comps.length > 0) { + startOffset = comps[0].getX(); + } + + int start = startOffset; + int end = targetX; + + int duration = 300; // ms + int fps = 60; + int delay = 1000 / fps; + int steps = Math.max(1, duration / delay); + final int[] step = {0}; + + Timer timer = new Timer(delay, null); + timer.addActionListener((ActionEvent e) -> { + step[0]++; + double t = (double) step[0] / steps; + // ease in-out cubic + double tt = t < 0.5 ? 4 * t * t * t : 1 - Math.pow(-2 * t + 2, 3) / 2; + int cur = (int) Math.round(start + (end - start) * tt); + + // 平移所有在 layeredPane 中(除背景)组件 + for (Component c : layeredPane.getComponents()) { + if (c instanceof JPanel && c.isVisible()) { + // 计算原始索引根据名字 + String name = c.getName(); + // 我们之前把panel放在 x = idx * w ; 现在把它设置为 idx*w + cur + int idx = 0; + if ("login".equals(name)) idx = 0; + else if ("register".equals(name)) idx = 1; + else if ("forgot".equals(name)) idx = 2; + c.setLocation(idx * w + cur, 0); + } + } + + layeredPane.repaint(); + + if (step[0] >= steps) { + timer.stop(); + } + }); + timer.setInitialDelay(0); + timer.start(); + } + + private JPanel buildLoginPanel() { + JPanel p = new JPanel(null); + p.setOpaque(false); + p.setName("login"); + int w = DIALOG_WIDTH - 40; + int h = DIALOG_HEIGHT - 40; + + // 标题区 + JLabel appTitle = new JLabel("AXIS"); + appTitle.setFont(new Font("微软雅黑", Font.BOLD, 28)); + appTitle.setForeground(Color.WHITE); + appTitle.setBounds(28, 20, w - 56, 36); + + JLabel subtitle = new JLabel("安全认证 — 请登录以继续"); + subtitle.setFont(new Font("微软雅黑", Font.PLAIN, 12)); + subtitle.setForeground(new Color(0xA7AEB5)); + subtitle.setBounds(28, 56, w - 56, 18); + + p.add(appTitle); + p.add(subtitle); + + // 卡片内控件起始 y + int startY = 96; + int fieldW = Math.min(360, w - 56); + int fieldX = (w - fieldW) / 2; + + // Email + JLabel emailLabel = new JLabel("账号"); + emailLabel.setForeground(new Color(0x99A0A7)); + emailLabel.setFont(new Font("微软雅黑", Font.PLAIN, 13)); + emailLabel.setBounds(fieldX, startY, fieldW, 18); + + loginEmailField = new JTextField(); + styleInput(loginEmailField); + loginEmailField.setBounds(fieldX, startY + 22, fieldW, 44); + loginEmailField.putClientProperty("JTextField.placeholderText", "邮箱或手机号"); + + // Password + JLabel pwdLabel = new JLabel("密码"); + pwdLabel.setForeground(new Color(0x99A0A7)); + pwdLabel.setFont(new Font("微软雅黑", Font.PLAIN, 13)); + pwdLabel.setBounds(fieldX, startY + 22 + 44 + 12, fieldW, 18); + + loginPasswordField = new JPasswordField(); + styleInput(loginPasswordField); + loginPasswordField.setBounds(fieldX, startY + 22 + 44 + 12 + 20, fieldW - 48, 44); + loginPasswordField.putClientProperty("JTextField.placeholderText", "请输入密码"); + + // eye toggle + JToggleButton eyeBtn = new JToggleButton("显示"); + eyeBtn.setFont(new Font("微软雅黑", Font.PLAIN, 12)); + eyeBtn.setFocusable(false); + eyeBtn.setBorderPainted(false); + eyeBtn.setContentAreaFilled(true); + eyeBtn.setBackground(new Color(0x39424A)); + eyeBtn.setForeground(Color.WHITE); + eyeBtn.setBounds(fieldX + fieldW - 44, startY + 22 + 44 + 12 + 20, 44, 44); + eyeBtn.addActionListener(e -> { + if (eyeBtn.isSelected()) loginPasswordField.setEchoChar((char) 0); + else loginPasswordField.setEchoChar('•'); + }); + + // 登录按钮(占满宽度) + JButton loginBtn = new JButton("立即登录"); + stylePrimaryButton(loginBtn); + loginBtn.setBounds(fieldX, startY + 22 + 44 + 12 + 20 + 44 + 22, fieldW, 48); + loginBtn.addActionListener(e -> doLogin()); + + // 链接区域(注册 / 忘记密码) — 点击切换到对应面板 + JButton toRegister = createTextLink("注册账号"); + toRegister.setBounds(fieldX, startY + 22 + 44 + 12 + 20 + 44 + 22 + 60, 120, 20); + toRegister.addActionListener(e -> slideTo(1)); + + JButton toForgot = createTextLink("忘记密码"); + toForgot.setBounds(fieldX + fieldW - 120, startY + 22 + 44 + 12 + 20 + 44 + 22 + 60, 120, 20); + toForgot.addActionListener(e -> slideTo(2)); + + // footer + JLabel footer = new JLabel("使用你的 AXIS 账户进行登录。"); + footer.setForeground(new Color(0x8F969C)); + footer.setFont(new Font("微软雅黑", Font.PLAIN, 11)); + footer.setBounds(fieldX, h - 44, fieldW, 18); + + p.add(emailLabel); + p.add(loginEmailField); + p.add(pwdLabel); + p.add(loginPasswordField); + p.add(eyeBtn); + p.add(loginBtn); + p.add(toRegister); + p.add(toForgot); + p.add(footer); + + return p; + } + + private JPanel buildRegisterPanel() { + JPanel p = new JPanel(null); + p.setOpaque(false); + p.setName("register"); + int w = DIALOG_WIDTH - 40; + int h = DIALOG_HEIGHT - 40; + + JLabel title = new JLabel("创建账号"); + title.setFont(new Font("微软雅黑", Font.BOLD, 24)); + title.setForeground(Color.WHITE); + title.setBounds(28, 20, w - 56, 36); + + JLabel desc = new JLabel("快速创建你的 AXIS 帐号"); + desc.setFont(new Font("微软雅黑", Font.PLAIN, 12)); + desc.setForeground(new Color(0xA7AEB5)); + desc.setBounds(28, 56, w - 56, 18); + + p.add(title); + p.add(desc); + + int startY = 96; + int fieldW = Math.min(360, w - 56); + int fieldX = (w - fieldW) / 2; + + // 用户名 + JLabel nameLabel = new JLabel("用户名"); + nameLabel.setForeground(new Color(0x99A0A7)); + nameLabel.setFont(new Font("微软雅黑", Font.PLAIN, 13)); + nameLabel.setBounds(fieldX, startY, fieldW, 18); + + JTextField nameField = new JTextField(); + styleInput(nameField); + nameField.setBounds(fieldX, startY + 22, fieldW, 44); + + // 邮箱 + JLabel emailLabel = new JLabel("邮箱"); + emailLabel.setForeground(new Color(0x99A0A7)); + emailLabel.setFont(new Font("微软雅黑", Font.PLAIN, 13)); + emailLabel.setBounds(fieldX, startY + 22 + 44 + 12, fieldW, 18); + + JTextField emailField = new JTextField(); + styleInput(emailField); + emailField.setBounds(fieldX, startY + 22 + 44 + 12 + 20, fieldW, 44); + + // 密码 + JLabel pwdLabel = new JLabel("密码"); + pwdLabel.setForeground(new Color(0x99A0A7)); + pwdLabel.setFont(new Font("微软雅黑", Font.PLAIN, 13)); + pwdLabel.setBounds(fieldX, startY + 22 + 44 + 12 + 20 + 44 + 12, fieldW, 18); + + JPasswordField pwdField = new JPasswordField(); + styleInput(pwdField); + pwdField.setBounds(fieldX, startY + 22 + 44 + 12 + 20 + 44 + 12 + 20, fieldW, 44); + + // 确认密码 + JLabel confirmLabel = new JLabel("确认密码"); + confirmLabel.setForeground(new Color(0x99A0A7)); + confirmLabel.setFont(new Font("微软雅黑", Font.PLAIN, 13)); + confirmLabel.setBounds(fieldX, startY + 22 + 44 + 12 + 20 + 44 + 12 + 20 + 44 + 12, fieldW, 18); + + JPasswordField confirmField = new JPasswordField(); + styleInput(confirmField); + confirmField.setBounds(fieldX, startY + 22 + 44 + 12 + 20 + 44 + 12 + 20 + 44 + 12 + 20, fieldW, 44); + + // 注册按钮 + JButton regBtn = new JButton("创建账号"); + stylePrimaryButton(regBtn); + regBtn.setBounds(fieldX, startY + 22 + 44 + 12 + 20 + 44 + 12 + 20 + 44 + 12 + 20 + 44 + 18, fieldW, 48); + + regBtn.addActionListener(e -> { + String name = nameField.getText().trim(); + String email = emailField.getText().trim(); + String pwd = new String(pwdField.getPassword()); + String confirm = new String(confirmField.getPassword()); + + if (name.isEmpty() || email.isEmpty() || pwd.isEmpty() || confirm.isEmpty()) { + JOptionPane.showMessageDialog(dialog, "请完整填写注册信息", "注册错误", JOptionPane.ERROR_MESSAGE); + return; + } + if (!pwd.equals(confirm)) { + JOptionPane.showMessageDialog(dialog, "两次输入的密码不一致", "注册错误", JOptionPane.ERROR_MESSAGE); + return; + } + boolean success = VerificationService.registerUser(name, email, pwd); + if (success) { + JOptionPane.showMessageDialog(dialog, "注册成功,请登录", "注册成功", JOptionPane.INFORMATION_MESSAGE); + slideTo(0); // 回到登录页面 + } else { + JOptionPane.showMessageDialog(dialog, "注册失败,请检查信息", "注册错误", JOptionPane.ERROR_MESSAGE); + } + }); + + // 返回登录链接 + JButton back = createTextLink("返回登录"); + back.setBounds(fieldX, regBtn.getY() + regBtn.getHeight() + 12, 120, 20); + back.addActionListener(e -> slideTo(0)); + + p.add(nameLabel); + p.add(nameField); + p.add(emailLabel); + p.add(emailField); + p.add(pwdLabel); + p.add(pwdField); + p.add(confirmLabel); + p.add(confirmField); + p.add(regBtn); + p.add(back); + + return p; + } + + private JPanel buildForgotPanel() { + JPanel p = new JPanel(null); + p.setOpaque(false); + p.setName("forgot"); + int w = DIALOG_WIDTH - 40; + int h = DIALOG_HEIGHT - 40; + + JLabel title = new JLabel("找回密码"); + title.setFont(new Font("微软雅黑", Font.BOLD, 24)); + title.setForeground(Color.WHITE); + title.setBounds(28, 20, w - 56, 36); + + JLabel desc = new JLabel("通过注册邮箱重置密码"); + desc.setFont(new Font("微软雅黑", Font.PLAIN, 12)); + desc.setForeground(new Color(0xA7AEB5)); + desc.setBounds(28, 56, w - 56, 18); + + p.add(title); + p.add(desc); + + int startY = 110; + int fieldW = Math.min(360, w - 56); + int fieldX = (w - fieldW) / 2; + + JLabel emailLabel = new JLabel("注册邮箱"); + emailLabel.setForeground(new Color(0x99A0A7)); + emailLabel.setFont(new Font("微软雅黑", Font.PLAIN, 13)); + emailLabel.setBounds(fieldX, startY, fieldW, 18); + + JTextField emailField = new JTextField(); + styleInput(emailField); + emailField.setBounds(fieldX, startY + 22, fieldW, 44); + + JButton sendBtn = new JButton("发送重置邮件"); + stylePrimaryButton(sendBtn); + sendBtn.setBounds(fieldX, startY + 22 + 44 + 22, fieldW, 48); + + sendBtn.addActionListener(e -> { + String email = emailField.getText().trim(); + if (email.isEmpty()) { + JOptionPane.showMessageDialog(dialog, "请输入注册邮箱", "错误", JOptionPane.ERROR_MESSAGE); + return; + } + if (VerificationService.sendPasswordReset(email)) { + JOptionPane.showMessageDialog(dialog, "重置邮件已发送,请查收", "成功", JOptionPane.INFORMATION_MESSAGE); + slideTo(0); + } else { + JOptionPane.showMessageDialog(dialog, "发送失败或邮箱未注册", "失败", JOptionPane.ERROR_MESSAGE); + } + }); + + JButton back = createTextLink("返回登录"); + back.setBounds(fieldX, sendBtn.getY() + sendBtn.getHeight() + 12, 120, 20); + back.addActionListener(e -> slideTo(0)); + + p.add(emailLabel); + p.add(emailField); + p.add(sendBtn); + p.add(back); + + return p; + } + + private void doLogin() { + String email = loginEmailField.getText().trim(); + String password = new String(loginPasswordField.getPassword()).trim(); + + if (email.isEmpty() || password.isEmpty()) { + JOptionPane.showMessageDialog(dialog, "请输入完整的登录信息", "验证错误", JOptionPane.ERROR_MESSAGE); + return; + } + + OnlineVerification onlineVerification = OnlineVerification.validateLogin(email, password); + if (onlineVerification == null) { + String err = OnlineVerification.errorMessage != null && !OnlineVerification.errorMessage.trim().isEmpty() + ? OnlineVerification.errorMessage + : "验证失败,请重试"; + JOptionPane.showMessageDialog(dialog, err, "验证错误", JOptionPane.ERROR_MESSAGE); + return; + } + + loginResult.set(VerificationService.determineUserType(onlineVerification)); + dialog.dispose(); + } + + + // 通用输入框样式 + private void styleInput(JComponent comp) { + comp.setFont(new Font("微软雅黑", Font.PLAIN, 14)); + comp.setBackground(new Color(0x2F3336)); + comp.setForeground(new Color(0xE8ECEF)); + comp.setBorder(BorderFactory.createCompoundBorder( + new RoundBorder(8, new Color(0x3A3F42)), + BorderFactory.createEmptyBorder(10, 12, 10, 12) + )); + if (comp instanceof JTextComponent) ((JTextComponent) comp).setCaretColor(new Color(0x9AA0A6)); + } + + // 主要操作按钮样式(主色) + private void stylePrimaryButton(AbstractButton b) { + b.setFont(new Font("微软雅黑", Font.BOLD, 14)); + b.setForeground(Color.WHITE); + b.setBackground(new Color(0x2B79D0)); + b.setBorderPainted(false); + b.setFocusPainted(false); + b.setOpaque(true); + b.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR)); + } + + private JButton createTextLink(String text) { + JButton btn = new JButton(text); + btn.setFont(new Font("微软雅黑", Font.PLAIN, 12)); + btn.setForeground(new Color(0x79A6FF)); + btn.setBorderPainted(false); + btn.setContentAreaFilled(false); + btn.setFocusPainted(false); + btn.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR)); + return btn; } private void setupLookAndFeel() { try { UIManager.setLookAndFeel(new FlatDarculaLaf()); - // 自定义输入框样式 UIManager.put("Component.arc", 12); UIManager.put("TextComponent.arc", 12); - UIManager.put("Button.arc", 8); - UIManager.put("ProgressBar.arc", 8); - UIManager.put("TextComponent.background", new Color(0x383838)); - UIManager.put("TextField.placeholderForeground", new Color(0x808080)); - } catch (UnsupportedLookAndFeelException e) { - e.printStackTrace(); + UIManager.put("Button.arc", 10); + + UIManager.put("Panel.background", new Color(0x202225)); + UIManager.put("TextComponent.background", new Color(0x2F3336)); + UIManager.put("TextComponent.foreground", new Color(0xE8ECEF)); + } catch (UnsupportedLookAndFeelException ex) { + ex.printStackTrace(); } } - private void createMainDialog() { - dialog = new JDialog((Frame) null, "AXIS 安全认证", true); - dialog.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE); - dialog.setSize(380, 500); - dialog.setLocationRelativeTo(null); - dialog.setResizable(false); - dialog.setLayout(new BorderLayout()); - } - - private void buildLoginUI() { - JPanel mainPanel = new JPanel(); - mainPanel.setLayout(new BoxLayout(mainPanel, BoxLayout.Y_AXIS)); - mainPanel.setBorder(BorderFactory.createEmptyBorder(30, 30, 30, 30)); - - JLabel titleLabel = new JLabel("欢迎登录"); - titleLabel.setFont(new Font("微软雅黑", Font.BOLD, 24)); - titleLabel.setAlignmentX(Component.CENTER_ALIGNMENT); - mainPanel.add(titleLabel); - mainPanel.add(Box.createRigidArea(new Dimension(0, 30))); - - JPanel inputContainer = new JPanel(); - inputContainer.setLayout(new BoxLayout(inputContainer, BoxLayout.Y_AXIS)); - inputContainer.setOpaque(false); - inputContainer.setAlignmentX(Component.CENTER_ALIGNMENT); - - inputContainer.add(createInputField("账号", buildEmailField())); - inputContainer.add(Box.createRigidArea(new Dimension(0, 10))); - - inputContainer.add(createInputField("密码", buildPasswordField())); - - mainPanel.add(inputContainer); - mainPanel.add(Box.createRigidArea(new Dimension(0, 30))); - - JButton loginButton = createLoginButton(); - loginButton.setAlignmentX(Component.CENTER_ALIGNMENT); - mainPanel.add(loginButton); - - JPanel linksPanel = createUtilityLinks(); - linksPanel.setAlignmentX(Component.CENTER_ALIGNMENT); - mainPanel.add(Box.createRigidArea(new Dimension(0, 30))); - mainPanel.add(linksPanel); - - mainPanel.add(Box.createVerticalGlue()); - - dialog.add(mainPanel, BorderLayout.CENTER); - } - - private JComponent buildEmailField() { - emailField = new JTextField(); - customizeTextField(emailField, "请输入邮箱或手机号"); - return emailField; - } - - private JComponent buildPasswordField() { - JPanel passwordPanel = new JPanel(new BorderLayout()); - passwordPanel.setOpaque(false); - passwordPanel.setBorder(new RoundBorder(8, new Color(0x454545))); - - // 密码输入框 - passwordField = new JPasswordField(); - passwordField.setFont(new Font("微软雅黑", Font.PLAIN, 14)); - passwordField.putClientProperty("JTextField.placeholderText", "请输入密码"); - passwordField.setMaximumSize(new Dimension(FIELD_WIDTH, FIELD_HEIGHT)); - passwordField.setPreferredSize(new Dimension(FIELD_WIDTH, FIELD_HEIGHT)); - passwordField.setBorder(BorderFactory.createEmptyBorder(10, 15, 10, 5)); - - passwordPanel.add(passwordField, BorderLayout.CENTER); - - // 显示密码按钮 - JPanel togglePanel = new JPanel(new BorderLayout()); - togglePanel.setOpaque(false); - togglePanel.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 10)); - - showPasswordCheckBox = new JCheckBox(); - showPasswordCheckBox.setOpaque(false); - showPasswordCheckBox.setPreferredSize(new Dimension(32, 32)); - showPasswordCheckBox.setBackground(new Color(0x46494B)); - showPasswordCheckBox.setIcon(UIManager.getIcon("PasswordView.icon")); - showPasswordCheckBox.setSelectedIcon(UIManager.getIcon("PasswordHide.icon")); - showPasswordCheckBox.addActionListener(e -> togglePasswordVisibility()); - togglePanel.add(showPasswordCheckBox, BorderLayout.CENTER); - - passwordPanel.add(togglePanel, BorderLayout.EAST); - return passwordPanel; - } - - private void customizeTextField(JComponent field, String placeholder) { - field.setPreferredSize(new Dimension(FIELD_WIDTH, FIELD_HEIGHT)); - field.setMaximumSize(new Dimension(FIELD_WIDTH, FIELD_HEIGHT)); - field.putClientProperty("JComponent.roundRect", true); - field.putClientProperty("JTextField.placeholderText", placeholder); - field.setFont(new Font("微软雅黑", Font.PLAIN, 14)); - field.setBorder(BorderFactory.createCompoundBorder( - new RoundBorder(8, new Color(0x454545)), - BorderFactory.createEmptyBorder(10, 15, 10, 15) - )); - } - - private JPanel createInputField(String label, JComponent field) { - JPanel panel = new JPanel(); - panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS)); - panel.setOpaque(false); - panel.setMaximumSize(new Dimension(280, 62)); - - JLabel titleLabel = new JLabel(label); - titleLabel.setFont(new Font("微软雅黑", Font.PLAIN, 13)); - titleLabel.setForeground(new Color(0x9E9E9E)); - titleLabel.setAlignmentX(Component.LEFT_ALIGNMENT); - - panel.add(titleLabel); - panel.add(Box.createVerticalStrut(8)); - panel.add(field); - - return panel; - } - - private JButton createLoginButton() { - JButton button = new JButton("立即登录"); - button.setFont(new Font("微软雅黑", Font.BOLD, 14)); - button.setForeground(Color.WHITE); - button.setBackground(new Color(0x2B579A)); - - button.setPreferredSize(new Dimension(285, 40)); - button.setMaximumSize(new Dimension(285, 40)); - - button.setAlignmentX(Component.CENTER_ALIGNMENT); - - button.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR)); - button.addActionListener(e -> attemptLogin()); - - // 悬停效果 - button.addMouseListener(new java.awt.event.MouseAdapter() { - public void mouseEntered(java.awt.event.MouseEvent evt) { - button.setBackground(new Color(0x3C6DB0)); - } - - public void mouseExited(java.awt.event.MouseEvent evt) { - button.setBackground(new Color(0x2B579A)); - } - }); - - return button; - } - + // 圆角边框 private static class RoundBorder extends LineBorder { private final int radius; @@ -214,222 +531,9 @@ public class LoginWindow { public void paintBorder(Component c, Graphics g, int x, int y, int width, int height) { Graphics2D g2 = (Graphics2D) g.create(); g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); - g2.drawRoundRect(x, y, width-1, height-1, radius, radius); + g2.setColor(lineColor); + g2.drawRoundRect(x, y, width - 1, height - 1, radius, radius); g2.dispose(); } } - - private JPanel createUtilityLinks() { - JPanel panel = new JPanel(); - panel.setLayout(new BoxLayout(panel, BoxLayout.X_AXIS)); - panel.setOpaque(false); - - JButton registerBtn = createTextButton("注册账号", this::showRegister); - JButton forgotBtn = createTextButton("忘记密码", this::showForgotPassword); - - panel.add(Box.createHorizontalGlue()); - panel.add(registerBtn); - panel.add(Box.createHorizontalStrut(15)); - panel.add(forgotBtn); - panel.add(Box.createHorizontalGlue()); - - return panel; - } - - private JButton createTextButton(String text, Runnable action) { - JButton button = new JButton(text); - button.setForeground(new Color(0x8AB4F8)); - button.setFont(new Font("微软雅黑", Font.PLAIN, 12)); - button.setContentAreaFilled(false); - button.setBorderPainted(false); - button.setFocusPainted(false); - button.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR)); - button.addActionListener(e -> action.run()); - return button; - } - - private void togglePasswordVisibility() { - if (showPasswordCheckBox.isSelected()) { - passwordField.setEchoChar((char) 0); - } else { - passwordField.setEchoChar('•'); - } - } - - private void attemptLogin() { - String email = emailField.getText().trim(); - String password = new String(passwordField.getPassword()).trim(); - - if (email.isEmpty() || password.isEmpty()) { - showError("请输入完整的登录信息"); - return; - } - - OnlineVerification onlineVerification = OnlineVerification.validateLogin(email, password); - loginResult.set(VerificationService.determineUserType(onlineVerification)); - - dialog.dispose(); - } - - private void showError(String message) { - JOptionPane.showMessageDialog(dialog, message, "验证错误", - JOptionPane.ERROR_MESSAGE); - } - - private void showRegister() { - JDialog registerDialog = new JDialog(dialog, "注册新账号", true); - registerDialog.setSize(380, 500); - registerDialog.setLocationRelativeTo(dialog); - registerDialog.setResizable(false); - registerDialog.setLayout(new BorderLayout()); - - JPanel mainPanel = new JPanel(); - mainPanel.setLayout(new BoxLayout(mainPanel, BoxLayout.Y_AXIS)); - mainPanel.setBorder(BorderFactory.createEmptyBorder(30, 30, 30, 30)); - - // 标题 - JLabel titleLabel = new JLabel("新用户注册"); - titleLabel.setFont(new Font("微软雅黑", Font.BOLD, 24)); - titleLabel.setAlignmentX(Component.CENTER_ALIGNMENT); - mainPanel.add(titleLabel); - mainPanel.add(Box.createRigidArea(new Dimension(0, 30))); - - // 输入容器 - JPanel inputContainer = new JPanel(); - inputContainer.setLayout(new BoxLayout(inputContainer, BoxLayout.Y_AXIS)); - inputContainer.setOpaque(false); - - // 用户名 - JTextField usernameField = new JTextField(); - customizeTextField(usernameField, "请输入用户名"); - inputContainer.add(createInputField("用户名", usernameField)); - inputContainer.add(Box.createRigidArea(new Dimension(0, 10))); - - // 邮箱 - JTextField emailField = new JTextField(); - customizeTextField(emailField, "请输入邮箱"); - inputContainer.add(createInputField("邮箱", emailField)); - inputContainer.add(Box.createRigidArea(new Dimension(0, 10))); - - // 密码 - JPasswordField passwordField = new JPasswordField(); - customizeTextField(passwordField, "请输入密码"); - inputContainer.add(createInputField("密码", passwordField)); - inputContainer.add(Box.createRigidArea(new Dimension(0, 10))); - - // 确认密码 - JPasswordField confirmField = new JPasswordField(); - customizeTextField(confirmField, "请再次输入密码"); - inputContainer.add(createInputField("确认密码", confirmField)); - - mainPanel.add(inputContainer); - mainPanel.add(Box.createRigidArea(new Dimension(0, 30))); - - // 注册按钮 - JButton regButton = new JButton("立即注册"); - styleButton(regButton); - regButton.addActionListener(e -> { - String pwd = new String(passwordField.getPassword()); - String confirm = new String(confirmField.getPassword()); - if(!pwd.equals(confirm)) { - JOptionPane.showMessageDialog(registerDialog, "两次输入的密码不一致", "注册错误", - JOptionPane.ERROR_MESSAGE); - return; - } - // 调用验证服务 - boolean success = VerificationService.registerUser( - usernameField.getText(), - emailField.getText(), - pwd - ); - if(success) { - JOptionPane.showMessageDialog(registerDialog, "注册成功,请登录", "注册成功", - JOptionPane.INFORMATION_MESSAGE); - registerDialog.dispose(); - } else { - JOptionPane.showMessageDialog(registerDialog, "注册失败,请检查信息", "注册错误", - JOptionPane.ERROR_MESSAGE); - } - }); - mainPanel.add(regButton); - - // 返回登录链接 - JButton backBtn = createTextButton("返回登录", registerDialog::dispose); - backBtn.setAlignmentX(Component.CENTER_ALIGNMENT); - mainPanel.add(Box.createRigidArea(new Dimension(0, 15))); - mainPanel.add(backBtn); - - registerDialog.add(mainPanel, BorderLayout.CENTER); - registerDialog.setVisible(true); - } - - private void showForgotPassword() { - JDialog forgotDialog = new JDialog(dialog, "找回密码", true); - forgotDialog.setSize(380, 350); - forgotDialog.setLocationRelativeTo(dialog); - forgotDialog.setResizable(false); - forgotDialog.setLayout(new BorderLayout()); - - JPanel mainPanel = new JPanel(); - mainPanel.setLayout(new BoxLayout(mainPanel, BoxLayout.Y_AXIS)); - mainPanel.setBorder(BorderFactory.createEmptyBorder(30, 30, 30, 30)); - - JLabel titleLabel = new JLabel("找回密码"); - titleLabel.setFont(new Font("微软雅黑", Font.BOLD, 24)); - titleLabel.setAlignmentX(Component.CENTER_ALIGNMENT); - mainPanel.add(titleLabel); - mainPanel.add(Box.createRigidArea(new Dimension(0, 30))); - - // 邮箱输入 - JTextField emailField = new JTextField(); - customizeTextField(emailField, "请输入注册邮箱"); - mainPanel.add(createInputField("注册邮箱", emailField)); - mainPanel.add(Box.createRigidArea(new Dimension(0, 30))); - - // 提交按钮 - JButton submitBtn = new JButton("发送重置邮件"); - styleButton(submitBtn); - submitBtn.addActionListener(e -> { - if(VerificationService.sendPasswordReset(emailField.getText())) { - JOptionPane.showMessageDialog(forgotDialog, "重置邮件已发送,请查收", "操作成功", - JOptionPane.INFORMATION_MESSAGE); - forgotDialog.dispose(); - } else { - JOptionPane.showMessageDialog(forgotDialog, "邮箱未注册或发送失败", "操作失败", - JOptionPane.ERROR_MESSAGE); - } - }); - mainPanel.add(submitBtn); - - // 返回链接 - JButton backBtn = createTextButton("返回登录", forgotDialog::dispose); - backBtn.setAlignmentX(Component.CENTER_ALIGNMENT); - mainPanel.add(Box.createRigidArea(new Dimension(0, 15))); - mainPanel.add(backBtn); - - forgotDialog.add(mainPanel, BorderLayout.CENTER); - forgotDialog.setVisible(true); - } - - // 通用按钮样式方法 - private void styleButton(JButton button) { - button.setFont(new Font("微软雅黑", Font.BOLD, 14)); - button.setForeground(Color.WHITE); - button.setBackground(new Color(0x2B579A)); - button.setPreferredSize(new Dimension(285, 40)); - button.setMaximumSize(new Dimension(285, 40)); - button.setAlignmentX(Component.CENTER_ALIGNMENT); - button.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR)); - - // 悬停效果 - button.addMouseListener(new java.awt.event.MouseAdapter() { - public void mouseEntered(java.awt.event.MouseEvent evt) { - button.setBackground(new Color(0x3C6DB0)); - } - public void mouseExited(java.awt.event.MouseEvent evt) { - button.setBackground(new Color(0x2B579A)); - } - }); - } } - diff --git a/src/main/java/com/axis/innovators/box/verification/OnlineVerification.java b/src/main/java/com/axis/innovators/box/verification/OnlineVerification.java index 7da3658..56febc3 100644 --- a/src/main/java/com/axis/innovators/box/verification/OnlineVerification.java +++ b/src/main/java/com/axis/innovators/box/verification/OnlineVerification.java @@ -2,32 +2,31 @@ package com.axis.innovators.box.verification; /** * 在线验证用户身份 + * 用于报错用户的验证信息 * @author tzdwindows 7 */ public class OnlineVerification { public String onlineVerification; - public UserTags userTags; public String password; - - OnlineVerification(String onlineVerification, UserTags userTags){ - this.onlineVerification = onlineVerification; - this.userTags = userTags; - } + /* 我是错误信息,要返回错误请修改我 */ + public static String errorMessage = "用户不存在"; /** * 验证登录 - * @param identifier - * @param password + * @param identifier 账号 + * @param password 密码 */ OnlineVerification(String identifier, String password){ this.onlineVerification = identifier; this.password = password; } - public static OnlineVerification validateLogin(String identifier){ - return new OnlineVerification(identifier, UserTags.RegularUsers); - } - + /** + * 验证登录 + * @param identifier 账号 + * @param password 密码 + * @return 验证结果,如果返回null则表示验证失败,使用errorMessage获取验证失败的原因 + */ public static OnlineVerification validateLogin(String identifier, String password){ return new OnlineVerification(identifier, password); } diff --git a/src/main/java/com/axis/innovators/box/verification/UserTags.java b/src/main/java/com/axis/innovators/box/verification/UserTags.java index 53e5453..2d5d5f4 100644 --- a/src/main/java/com/axis/innovators/box/verification/UserTags.java +++ b/src/main/java/com/axis/innovators/box/verification/UserTags.java @@ -31,6 +31,11 @@ public enum UserTags { EnterpriseUsers; private OnlineVerification onlineVerification; + + /** + * 设置用户组信息 + * @param onlineVerification 用户验证结果信息 + */ void setUser(OnlineVerification onlineVerification) { this.onlineVerification = onlineVerification; } diff --git a/src/main/java/com/axis/innovators/box/verification/VerificationService.java b/src/main/java/com/axis/innovators/box/verification/VerificationService.java index cdbf950..0dd038f 100644 --- a/src/main/java/com/axis/innovators/box/verification/VerificationService.java +++ b/src/main/java/com/axis/innovators/box/verification/VerificationService.java @@ -4,6 +4,12 @@ package com.axis.innovators.box.verification; * @author tzdwindows 7 */ public class VerificationService { + + /** + * 确定用户类型 + * @param identifier 用户 + * @return 用户类型 + */ public static UserTags determineUserType(OnlineVerification identifier) { UserTags userTags = UserTags.RegularUsers; userTags.setUser(identifier); @@ -19,6 +25,13 @@ public class VerificationService { return true; } + /** + * 注册用户 + * @param text + * @param text1 + * @param pwd + * @return + */ public static boolean registerUser(String text, String text1, String pwd) { return true; } diff --git a/state/toolbox.properties b/state/toolbox.properties deleted file mode 100644 index e6cd80c..0000000 --- a/state/toolbox.properties +++ /dev/null @@ -1,4 +0,0 @@ -#Updated configuration -#Fri Mar 07 17:43:24 CST 2025 -password=safasf -verification=aasfsaf