extends Control # ============================================================================ # AuthScene.gd - 认证场景视图控制器 # ============================================================================ # 认证系统的视图层控制器,只负责UI相关的操作 # # 核心职责: # - UI控件的显示和隐藏 # - 用户输入的收集和传递 # - 错误提示的显示 # - 按钮状态的管理 # - Toast消息的显示 # # 业务逻辑: # - 所有业务逻辑都委托给AuthManager处理 # - 通过信号与AuthManager通信 # - 不包含任何验证逻辑或网络请求 # # 注意事项: # - 这是纯视图层,不处理业务逻辑 # - 通过事件系统与业务层解耦 # - 专注于用户体验和界面交互 # ============================================================================ # ============ 信号定义 ============ # 登录成功信号 - 传递给上层场景 signal login_success(username: String) # ============ UI节点引用 ============ # 主要容器和背景 @onready var background_image: TextureRect = $BackgroundImage # 背景图片 @onready var login_panel: Panel = $CenterContainer/LoginPanel # 登录面板 @onready var register_panel: Panel = $CenterContainer/RegisterPanel # 注册面板 @onready var title_label: Label = $CenterContainer/LoginPanel/VBoxContainer/TitleLabel # 标题标签 @onready var subtitle_label: Label = $CenterContainer/LoginPanel/VBoxContainer/SubtitleLabel # 副标题标签 @onready var whale_frame: TextureRect = $WhaleFrame # 鲸鱼装饰框 # 登录表单输入控件 @onready var login_username: LineEdit = $CenterContainer/LoginPanel/VBoxContainer/LoginForm/UsernameContainer/UsernameInput @onready var login_password: LineEdit = $CenterContainer/LoginPanel/VBoxContainer/LoginForm/PasswordContainer/PasswordInput @onready var login_verification: LineEdit = $CenterContainer/LoginPanel/VBoxContainer/LoginForm/VerificationContainer/VerificationInputContainer/VerificationInput # 登录表单错误提示标签 @onready var login_username_error: Label = $CenterContainer/LoginPanel/VBoxContainer/LoginForm/UsernameContainer/UsernameLabelContainer/UsernameError @onready var login_password_error: Label = $CenterContainer/LoginPanel/VBoxContainer/LoginForm/PasswordContainer/PasswordLabelContainer/PasswordError @onready var login_verification_error: Label = $CenterContainer/LoginPanel/VBoxContainer/LoginForm/VerificationContainer/VerificationLabelContainer/VerificationError # 登录表单容器(用于显示/隐藏) @onready var password_container: VBoxContainer = $CenterContainer/LoginPanel/VBoxContainer/LoginForm/PasswordContainer @onready var verification_container: VBoxContainer = $CenterContainer/LoginPanel/VBoxContainer/LoginForm/VerificationContainer # 登录相关按钮 @onready var get_code_btn: Button = $CenterContainer/LoginPanel/VBoxContainer/LoginForm/VerificationContainer/VerificationInputContainer/GetCodeBtn @onready var main_btn: Button = $CenterContainer/LoginPanel/VBoxContainer/MainButton @onready var login_btn: Button = $CenterContainer/LoginPanel/VBoxContainer/ButtonContainer/LoginBtn @onready var forgot_password_btn: Button = $CenterContainer/LoginPanel/VBoxContainer/BottomLinks/ForgotPassword @onready var register_link_btn: Button = $CenterContainer/LoginPanel/VBoxContainer/BottomLinks/RegisterLink # 注册表单输入控件 @onready var register_username: LineEdit = $CenterContainer/RegisterPanel/VBoxContainer/RegisterForm/UsernameContainer/UsernameInput @onready var register_email: LineEdit = $CenterContainer/RegisterPanel/VBoxContainer/RegisterForm/EmailContainer/EmailInput @onready var register_password: LineEdit = $CenterContainer/RegisterPanel/VBoxContainer/RegisterForm/PasswordContainer/PasswordInput @onready var register_confirm: LineEdit = $CenterContainer/RegisterPanel/VBoxContainer/RegisterForm/ConfirmContainer/ConfirmInput @onready var verification_input: LineEdit = $CenterContainer/RegisterPanel/VBoxContainer/RegisterForm/VerificationContainer/VerificationInputContainer/VerificationInput # 注册相关按钮 @onready var send_code_btn: Button = $CenterContainer/RegisterPanel/VBoxContainer/RegisterForm/VerificationContainer/VerificationInputContainer/SendCodeBtn @onready var register_btn: Button = $CenterContainer/RegisterPanel/VBoxContainer/ButtonContainer/RegisterBtn @onready var to_login_btn: Button = $CenterContainer/RegisterPanel/VBoxContainer/ButtonContainer/ToLoginBtn # 注册表单错误提示标签 @onready var register_username_error: Label = $CenterContainer/RegisterPanel/VBoxContainer/RegisterForm/UsernameContainer/UsernameLabelContainer/UsernameError @onready var register_email_error: Label = $CenterContainer/RegisterPanel/VBoxContainer/RegisterForm/EmailContainer/EmailLabelContainer/EmailError @onready var register_password_error: Label = $CenterContainer/RegisterPanel/VBoxContainer/RegisterForm/PasswordContainer/PasswordLabelContainer/PasswordError @onready var register_confirm_error: Label = $CenterContainer/RegisterPanel/VBoxContainer/RegisterForm/ConfirmContainer/ConfirmLabelContainer/ConfirmError @onready var verification_error: Label = $CenterContainer/RegisterPanel/VBoxContainer/RegisterForm/VerificationContainer/VerificationLabelContainer/VerificationError # Toast消息系统 @onready var toast_container: Control = $ToastContainer # Toast消息容器 # ============ 成员变量 ============ # 业务逻辑管理器 var auth_manager: AuthManager # Toast消息管理器 var toast_manager: ToastManager # 验证码冷却计时器 var cooldown_timer: Timer = null # 当前登录模式(从管理器同步) var current_login_mode: AuthManager.LoginMode = AuthManager.LoginMode.PASSWORD # ============ 生命周期方法 ============ # 初始化认证场景 func _ready(): _setup_controllers() # 初始化控制器 _connect_signals() # 连接信号 _setup_ui() # 设置UI初始状态 print("认证场景视图已加载") # 测试网络连接 auth_manager.test_network_connection() # 设置控制器 func _setup_controllers(): # 创建业务逻辑管理器 auth_manager = AuthManager.new() # 创建Toast管理器 toast_manager = ToastManager.new() toast_manager.setup(toast_container) # 连接管理器信号 _connect_controller_signals() # 连接管理器信号 func _connect_controller_signals(): # 登录相关信号 auth_manager.login_success.connect(_on_controller_login_success) auth_manager.login_failed.connect(_on_controller_login_failed) # 注册相关信号 auth_manager.register_success.connect(_on_controller_register_success) auth_manager.register_failed.connect(_on_controller_register_failed) # 验证码相关信号 auth_manager.verification_code_sent.connect(_on_controller_verification_code_sent) auth_manager.verification_code_failed.connect(_on_controller_verification_code_failed) # 表单验证信号 auth_manager.form_validation_failed.connect(_on_controller_form_validation_failed) # 网络状态信号 auth_manager.network_status_changed.connect(_on_controller_network_status_changed) # 按钮状态信号 auth_manager.button_state_changed.connect(_on_controller_button_state_changed) # Toast消息信号 auth_manager.show_toast_message.connect(_on_controller_show_toast_message) # 设置UI初始状态 func _setup_ui(): show_login_panel() _update_login_mode_ui() # 连接UI信号 func _connect_signals(): # 主要按钮信号 main_btn.pressed.connect(_on_main_button_pressed) # 登录界面按钮信号 login_btn.pressed.connect(_on_login_mode_toggle_pressed) forgot_password_btn.pressed.connect(_on_forgot_password_pressed) register_link_btn.pressed.connect(_on_register_link_pressed) get_code_btn.pressed.connect(_on_get_login_code_pressed) # 注册界面按钮信号 register_btn.pressed.connect(_on_register_pressed) to_login_btn.pressed.connect(_on_to_login_pressed) send_code_btn.pressed.connect(_on_send_code_pressed) # 回车键快捷登录 login_password.text_submitted.connect(_on_login_enter) # 表单失焦验证事件 _connect_validation_signals() # 实时输入验证事件 _connect_input_change_signals() # 连接表单验证信号 func _connect_validation_signals(): # 登录表单 login_username.focus_exited.connect(_on_login_username_focus_exited) login_password.focus_exited.connect(_on_login_password_focus_exited) login_verification.focus_exited.connect(_on_login_verification_focus_exited) # 注册表单 register_username.focus_exited.connect(_on_register_username_focus_exited) register_email.focus_exited.connect(_on_register_email_focus_exited) register_password.focus_exited.connect(_on_register_password_focus_exited) register_confirm.focus_exited.connect(_on_register_confirm_focus_exited) verification_input.focus_exited.connect(_on_verification_focus_exited) # 连接输入变化信号 func _connect_input_change_signals(): register_username.text_changed.connect(_on_register_username_text_changed) register_email.text_changed.connect(_on_register_email_text_changed) register_password.text_changed.connect(_on_register_password_text_changed) register_confirm.text_changed.connect(_on_register_confirm_text_changed) verification_input.text_changed.connect(_on_verification_text_changed) # ============ UI面板管理 ============ # 显示登录面板 func show_login_panel(): login_panel.visible = true register_panel.visible = false login_username.grab_focus() # 显示注册面板 func show_register_panel(): login_panel.visible = false register_panel.visible = true register_username.grab_focus() # ============ 登录模式管理 ============ # 更新登录模式UI func _update_login_mode_ui(): current_login_mode = auth_manager.get_current_login_mode() if current_login_mode == AuthManager.LoginMode.PASSWORD: # 密码登录模式 login_btn.text = "验证码登录" forgot_password_btn.text = "忘记密码" # 显示密码输入框,隐藏验证码输入框 password_container.visible = true verification_container.visible = false # 清空验证码输入框和错误提示 login_verification.text = "" _hide_field_error(login_verification_error) else: # VERIFICATION mode # 验证码登录模式 login_btn.text = "密码登录" forgot_password_btn.text = "获取验证码" # 隐藏密码输入框,显示验证码输入框 password_container.visible = false verification_container.visible = true # 清空密码输入框和错误提示 login_password.text = "" _hide_field_error(login_password_error) # ============ 按钮事件处理 ============ # 主按钮点击事件 func _on_main_button_pressed(): if current_login_mode == AuthManager.LoginMode.PASSWORD: _execute_password_login() else: _execute_verification_login() # 执行密码登录 func _execute_password_login(): var username = login_username.text.strip_edges() var password = login_password.text auth_manager.execute_password_login(username, password) # 执行验证码登录 func _execute_verification_login(): var identifier = login_username.text.strip_edges() var verification_code = login_verification.text.strip_edges() auth_manager.execute_verification_login(identifier, verification_code) # 登录模式切换按钮 func _on_login_mode_toggle_pressed(): auth_manager.toggle_login_mode() _update_login_mode_ui() # 清空输入框和错误提示 login_username.text = "" login_password.text = "" login_verification.text = "" _hide_field_error(login_username_error) _hide_field_error(login_password_error) _hide_field_error(login_verification_error) # 注册按钮点击事件 func _on_register_pressed(): var username = register_username.text.strip_edges() var email = register_email.text.strip_edges() var password = register_password.text var confirm_password = register_confirm.text var verification_code = verification_input.text.strip_edges() auth_manager.execute_register(username, email, password, confirm_password, verification_code) # 发送邮箱验证码按钮 func _on_send_code_pressed(): var email = register_email.text.strip_edges() auth_manager.send_email_verification_code(email) # 开始冷却计时器 _start_cooldown_timer(email) # 获取登录验证码按钮 func _on_get_login_code_pressed(): var identifier = login_username.text.strip_edges() auth_manager.send_login_verification_code(identifier) # 忘记密码按钮 func _on_forgot_password_pressed(): var identifier = login_username.text.strip_edges() if current_login_mode == AuthManager.LoginMode.PASSWORD: # 密码登录模式:发送密码重置验证码 auth_manager.send_password_reset_code(identifier) else: # 验证码登录模式:发送登录验证码 auth_manager.send_login_verification_code(identifier) # 跳转到注册面板 func _on_register_link_pressed(): show_register_panel() # 返回登录面板 func _on_to_login_pressed(): show_login_panel() # 回车键登录 func _on_login_enter(_text: String): _on_main_button_pressed() # ============ 控制器信号处理 ============ # 登录成功处理 func _on_controller_login_success(username: String) -> void: # 清空表单 login_username.text = "" login_password.text = "" login_verification.text = "" _hide_field_error(login_username_error) _hide_field_error(login_password_error) _hide_field_error(login_verification_error) # 设置 token 给 ChatManager(用于 WebSocket 聊天认证) var token: String = auth_manager.get_access_token() if not token.is_empty(): ChatManager.set_game_token(token) print("✅ 已设置 ChatManager token: ", token.substr(0, 20) + "...") # 发送登录成功信号给上层 login_success.emit(username) # 登录失败处理 func _on_controller_login_failed(_message: String): # 登录失败时不需要额外处理,Toast已经显示了错误信息 pass # 注册成功处理 func _on_controller_register_success(_message: String): # 清空注册表单 _clear_register_form() # 切换到登录面板 show_login_panel() # 将注册时的用户名填入登录框 login_username.text = register_username.text.strip_edges() # 注册失败处理 func _on_controller_register_failed(_message: String): # 注册失败时不需要额外处理,Toast已经显示了错误信息 pass # 验证码发送成功处理 func _on_controller_verification_code_sent(_message: String): # 验证码发送成功,冷却计时器已经在按钮点击时启动 pass # 验证码发送失败处理 func _on_controller_verification_code_failed(_message: String): # 重置验证码按钮状态 _reset_verification_button() # 表单验证失败处理 func _on_controller_form_validation_failed(field: String, message: String): match field: "username": _show_field_error(login_username_error, message) login_username.grab_focus() "password": _show_field_error(login_password_error, message) login_password.grab_focus() "verification": if current_login_mode == AuthManager.LoginMode.VERIFICATION: _show_field_error(login_verification_error, message) login_verification.grab_focus() else: _show_field_error(verification_error, message) verification_input.grab_focus() "email": _show_field_error(register_email_error, message) register_email.grab_focus() "confirm": _show_field_error(register_confirm_error, message) register_confirm.grab_focus() # 网络状态变化处理 func _on_controller_network_status_changed(network_connected: bool, message: String): # 可以在这里添加网络状态指示器 print("网络状态: ", "连接" if network_connected else "断开", " - ", message) # 按钮状态变化处理 func _on_controller_button_state_changed(button_name: String, is_loading: bool, text: String): match button_name: "main_btn": _set_button_state(main_btn, is_loading, text) "register_btn": _set_button_state(register_btn, is_loading, text) "get_code_btn": _set_button_state(get_code_btn, is_loading, text) "forgot_password_btn": _set_button_state(forgot_password_btn, is_loading, text) # Toast消息处理 func _on_controller_show_toast_message(message: String, is_success: bool): toast_manager.show_toast(message, is_success) # ============ 验证码冷却管理 ============ # 开始冷却计时器 func _start_cooldown_timer(_email: String): if cooldown_timer != null: cooldown_timer.queue_free() send_code_btn.disabled = true send_code_btn.text = "重新发送(60)" cooldown_timer = Timer.new() add_child(cooldown_timer) cooldown_timer.wait_time = 1.0 cooldown_timer.timeout.connect(_on_cooldown_timer_timeout) cooldown_timer.start() # 冷却计时器超时处理 func _on_cooldown_timer_timeout(): var remaining_time = auth_manager.get_remaining_cooldown_time(register_email.text.strip_edges()) if remaining_time > 0: send_code_btn.text = "重新发送(%d)" % remaining_time else: send_code_btn.text = "重新发送" send_code_btn.disabled = false if cooldown_timer != null: cooldown_timer.queue_free() cooldown_timer = null # 重置验证码按钮状态 func _reset_verification_button(): if cooldown_timer != null: cooldown_timer.queue_free() cooldown_timer = null send_code_btn.disabled = false send_code_btn.text = "发送验证码" # ============ UI工具方法 ============ # 设置按钮状态 func _set_button_state(button: Button, is_loading: bool, text: String): button.disabled = is_loading button.text = text # 显示字段错误 func _show_field_error(error_label: Label, message: String): error_label.text = message error_label.visible = true # 隐藏字段错误 func _hide_field_error(error_label: Label): error_label.visible = false # 清空注册表单 func _clear_register_form(): register_username.text = "" register_email.text = "" register_password.text = "" register_confirm.text = "" verification_input.text = "" _reset_verification_button() _hide_field_error(register_username_error) _hide_field_error(register_email_error) _hide_field_error(register_password_error) _hide_field_error(register_confirm_error) _hide_field_error(verification_error) # ============ 表单验证事件处理 ============ # 登录用户名失焦验证 func _on_login_username_focus_exited(): var username = login_username.text.strip_edges() if username.is_empty(): _show_field_error(login_username_error, "用户名不能为空") else: _hide_field_error(login_username_error) # 登录密码失焦验证 func _on_login_password_focus_exited(): var password = login_password.text if password.is_empty(): _show_field_error(login_password_error, "密码不能为空") else: _hide_field_error(login_password_error) # 登录验证码失焦验证 func _on_login_verification_focus_exited(): var verification_code = login_verification.text.strip_edges() var validation = auth_manager.validate_verification_code(verification_code) if not validation.valid: _show_field_error(login_verification_error, validation.message) else: _hide_field_error(login_verification_error) # 注册用户名失焦验证 func _on_register_username_focus_exited(): var username = register_username.text.strip_edges() var validation = auth_manager.validate_username(username) if not validation.valid: _show_field_error(register_username_error, validation.message) else: _hide_field_error(register_username_error) # 注册邮箱失焦验证 func _on_register_email_focus_exited(): var email = register_email.text.strip_edges() var validation = auth_manager.validate_email(email) if not validation.valid: _show_field_error(register_email_error, validation.message) else: _hide_field_error(register_email_error) # 注册密码失焦验证 func _on_register_password_focus_exited(): var password = register_password.text var validation = auth_manager.validate_password(password) if not validation.valid: _show_field_error(register_password_error, validation.message) else: _hide_field_error(register_password_error) # 如果确认密码不为空,重新验证确认密码 if not register_confirm.text.is_empty(): _on_register_confirm_focus_exited() # 注册确认密码失焦验证 func _on_register_confirm_focus_exited(): var password = register_password.text var confirm = register_confirm.text var validation = auth_manager.validate_confirm_password(password, confirm) if not validation.valid: _show_field_error(register_confirm_error, validation.message) else: _hide_field_error(register_confirm_error) # 验证码失焦验证 func _on_verification_focus_exited(): var code = verification_input.text.strip_edges() var validation = auth_manager.validate_verification_code(code) if not validation.valid: _show_field_error(verification_error, validation.message) else: _hide_field_error(verification_error) # ============ 实时输入验证事件 ============ # 注册用户名输入变化 func _on_register_username_text_changed(new_text: String): if register_username_error.visible and not new_text.is_empty(): _hide_field_error(register_username_error) # 注册邮箱输入变化 func _on_register_email_text_changed(new_text: String): if register_email_error.visible and not new_text.is_empty(): _hide_field_error(register_email_error) # 注册密码输入变化 func _on_register_password_text_changed(new_text: String): if register_password_error.visible and not new_text.is_empty(): _hide_field_error(register_password_error) # 注册确认密码输入变化 func _on_register_confirm_text_changed(new_text: String): if register_confirm_error.visible and not new_text.is_empty(): _hide_field_error(register_confirm_error) # 验证码输入变化 func _on_verification_text_changed(new_text: String): if verification_error.visible and not new_text.is_empty(): _hide_field_error(verification_error) # ============ 资源清理 ============ # 节点销毁时清理资源 func _exit_tree(): # 清理控制器 if auth_manager: auth_manager.cleanup() # 清理Toast管理器 if toast_manager: toast_manager.clear_all_toasts() # 清理计时器 if cooldown_timer != null: cooldown_timer.queue_free() cooldown_timer = null # 处理ESC键退出 func _input(event): if event.is_action_pressed("ui_cancel"): get_tree().quit()