package com.mathgenerator.ui; import com.mathgenerator.auth.User; import com.mathgenerator.model.Level; import com.mathgenerator.service.PaperService; import com.mathgenerator.service.UserService; import java.util.Optional; import java.util.Scanner; /** * 负责所有控制台用户界面的显示和交互。 */ public class ConsoleUI { private final Scanner scanner = new Scanner(System.in); private final UserService userService; private final PaperService paperService; /** * ConsoleUI的构造函数。 * 通过构造函数接收依赖的服务,这是一种常见的设计模式(依赖注入), * 使得UI层不负责创建服务,只负责使用。 * * @param userService 用户服务实例。 * @param paperService 试卷服务实例。 */ public ConsoleUI(UserService userService, PaperService paperService) { this.userService = userService; this.paperService = paperService; } /** * 启动并运行整个用户界面主循环。 */ public void run() { while (true) { // 在主循环中加入注册选项 printHeader("欢迎使用中小学数学卷子自动生成程序"); System.out.println("1. 用户登录"); System.out.println("2. 新用户注册"); System.out.println("3. 退出程序"); printSeparator(); System.out.print("请选择操作 (1-3): "); String choice = scanner.nextLine().trim(); switch (choice) { case "1" -> handleLogin().ifPresent(this::showUserMenu); case "2" -> handleRegistration(); case "3" -> { System.out.println("感谢使用,程序已退出。"); return; // 退出run()方法,结束程序 } default -> System.out.println("无效输入,请输入 1-3 之间的数字。"); } } } /** * 私有辅助方法,处理用户登录流程。 * * @return 登录成功的用户Optional,如果登录失败或格式错误则返回空Optional。 */ private Optional handleLogin() { printHeader("用户登录"); System.out.print("请输入用户名和密码 (用空格隔开): \n> "); String[] credentials = scanner.nextLine().split("\\s+"); if (credentials.length != 2) { System.out.println("输入格式错误。"); return Optional.empty(); } // 调用新的UserService进行登录 Optional userOptional = userService.login(credentials[0], credentials[1]); if (userOptional.isEmpty()) { System.out.println("用户名或密码错误。"); } return userOptional; } /** * 新增方法:处理用户注册流程。 */ private void handleRegistration() { printHeader("新用户注册"); System.out.print("请输入新用户名: "); String username = scanner.nextLine().trim(); if (userService.findUserByUsername(username).isPresent()) { System.out.println("注册失败:该用户名已被占用。"); return; } System.out.print("请输入密码: "); String password = scanner.nextLine().trim(); Level level = selectLevelForRegistration(); if (level == null) { System.out.println("操作已取消。"); return; } if (userService.register(username, password, level)) { System.out.println("注册成功!现在您可以使用新账户登录了。"); } else { // 理论上,这里的失败分支不会被触发,因为我们已经提前检查了用户名 System.out.println("注册失败,发生未知错误。"); } } /** * 新增辅助方法:让用户在注册时选择学段。 */ private Level selectLevelForRegistration() { while (true) { printHeader("请为新用户选择默认的学段"); System.out.println("1. 小学"); System.out.println("2. 初中"); System.out.println("3. 高中"); System.out.println("0. 取消注册"); printSeparator(); System.out.print("请选择 (0-3): "); String choice = scanner.nextLine().trim(); switch (choice) { case "1": return Level.PRIMARY; case "2": return Level.JUNIOR_HIGH; case "3": return Level.SENIOR_HIGH; case "0": return null; // 用户取消 default: System.out.println("无效输入,请重新选择。"); } } } /** * 私有辅助方法,显示登录后的用户主菜单和处理用户操作。 * * @param user 当前已登录的用户对象。 */ private void showUserMenu(User user) { Level currentLevel = user.level(); System.out.println("\n登录成功! 欢迎 " + user.username()); System.out.println("当前选择为 " + currentLevel.getChineseName() + " 出题"); while (true) { printHeader("当前用户: " + user.username() + " | 当前难度: " + currentLevel.getChineseName()); System.out.println("1. 生成题目"); System.out.println("2. 切换难度级别"); System.out.println("3. 退出当前用户"); System.out.println("4. 退出程序"); printSeparator(); System.out.print("请选择操作 (1-4): "); String choice = scanner.nextLine().trim(); switch (choice) { case "1" -> handleGeneration(user, currentLevel); case "2" -> currentLevel = handleLevelSwitchMenu(currentLevel); case "3" -> { System.out.println("用户 " + user.username() + " 已退出。"); return; } case "4" -> { System.out.println("感谢使用,程序已退出。"); System.exit(0); } default -> System.out.println("无效输入,请输入 1-4 之间的数字。"); } } } /** * 私有辅助方法,处理切换难度的子菜单,加入循环以处理无效输入。 * * @param currentLevel 当前的难度级别。 * @return 用户选择的新的难度级别,如果选择返回则为原级别。 */ private Level handleLevelSwitchMenu(Level currentLevel) { while (true) { // <-- 增加循环 printHeader("请选择难度级别"); System.out.println("1. 小学 (+, -, *, /, 括号)"); System.out.println("2. 初中 (包含平方、开根号)"); System.out.println("3. 高中 (包含三角函数)"); System.out.println("0. 返回主菜单"); printSeparator(); System.out.print("请选择 (0-3): "); String choice = scanner.nextLine().trim(); switch (choice) { case "1": System.out.println("难度已成功切换为 " + Level.PRIMARY.getChineseName() + "。"); return Level.PRIMARY; // 直接返回,退出循环 case "2": System.out.println("难度已成功切换为 " + Level.JUNIOR_HIGH.getChineseName() + "。"); return Level.JUNIOR_HIGH; // 直接返回,退出循环 case "3": System.out.println("难度已成功切换为 " + Level.SENIOR_HIGH.getChineseName() + "。"); return Level.SENIOR_HIGH; // 直接返回,退出循环 case "0": System.out.println("已返回主菜单。"); return currentLevel; // 返回当前难度,退出循环 default: System.out.println("无效输入,请输入 0-3 之间的数字。"); } } } /** * 私有辅助方法,处理生成题目的逻辑。 * * @param user 当前登录的用户。 * @param currentLevel 当前选择的难度级别。 */ private void handleGeneration(User user, Level currentLevel) { while (true) { printHeader("生成 " + currentLevel.getChineseName() + " 题目"); System.out.print("请输入生成题目数量 (10-30,输入 0 返回主菜单): "); String input = scanner.nextLine().trim(); try { int count = Integer.parseInt(input); if (count == 0) { System.out.println("已取消生成,返回主菜单。"); break; // 退出循环,返回主菜单 } if (count >= 10 && count <= 30) { paperService.createAndSavePaper(user, count, currentLevel); break; // 成功生成,退出循环,返回主菜单 } else { System.out.println("无效输入,题目数量必须在 10 到 30 之间。请重新输入。"); } } catch (NumberFormatException e) { System.out.println("无效输入,请输入一个有效的数字。请重新输入。"); } } } /** * 私有辅助方法,打印美化后的标题行。 * * @param title 要显示的标题文本。 */ private void printHeader(String title) { printSeparator(); System.out.println(title); printSeparator(); } /** * 私有辅助方法,打印分割线。 */ private void printSeparator() { System.out.println("======================================================"); } }