forked from datawhale/whale-town-front
- 添加登录场景(login_scene.tscn)和主菜单场景(main_menu_scene.tscn) - 实现认证管理器(AuthManager)用于用户登录和会话管理 - 添加核心服务:加密服务、存储服务、网络服务 - 配置项目主场景为登录场景 - 添加自动加载服务到项目配置 - 添加开发环境配置(VSCode、Claude) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
218 lines
6.4 KiB
GDScript
218 lines
6.4 KiB
GDScript
extends Control
|
|
|
|
## 登录界面控制器
|
|
## 处理登录界面的用户交互、输入验证、错误提示等
|
|
|
|
# UI 节点引用
|
|
@onready var passwordLoginTab: Button = $LoginPanel/PasswordLoginTab
|
|
@onready var codeLoginTab: Button = $LoginPanel/CodeLoginTab
|
|
@onready var usernameInput: LineEdit = $LoginPanel/UsernameInput
|
|
@onready var passwordInput: LineEdit = $LoginPanel/PasswordInput
|
|
@onready var togglePasswordButton: Button = $LoginPanel/TogglePasswordButton
|
|
@onready var rememberPasswordCheckBox: CheckBox = $LoginPanel/RememberPasswordCheckBox
|
|
@onready var autoLoginCheckBox: CheckBox = $LoginPanel/AutoLoginCheckBox
|
|
@onready var enterButton: TextureButton = $LoginPanel/EnterButton
|
|
@onready var forgotPasswordButton: LinkButton = $LoginPanel/ForgotPasswordButton
|
|
@onready var registerButton: LinkButton = $LoginPanel/RegisterButton
|
|
@onready var statusLabel: Label = $LoginPanel/StatusLabel
|
|
@onready var loadingOverlay: ColorRect = $LoadingOverlay
|
|
@onready var loadingLabel: Label = $LoadingOverlay/LoadingLabel
|
|
|
|
# 当前登录模式
|
|
enum LoginMode {
|
|
PASSWORD, # 密码登录
|
|
CODE # 验证码登录
|
|
}
|
|
var currentMode: LoginMode = LoginMode.PASSWORD
|
|
|
|
func _ready():
|
|
# 连接Tab按钮信号
|
|
passwordLoginTab.pressed.connect(_onPasswordTabPressed)
|
|
codeLoginTab.pressed.connect(_onCodeTabPressed)
|
|
|
|
# 连接主要按钮信号
|
|
enterButton.pressed.connect(_onEnterButtonPressed)
|
|
togglePasswordButton.pressed.connect(_onTogglePasswordPressed)
|
|
|
|
# 连接底部链接按钮
|
|
forgotPasswordButton.pressed.connect(_onForgotPasswordPressed)
|
|
registerButton.pressed.connect(_onRegisterPressed)
|
|
|
|
# 连接 AuthManager 信号
|
|
AuthManager.login_success.connect(_onLoginSuccess)
|
|
AuthManager.login_failed.connect(_onLoginFailed)
|
|
|
|
# 连接输入框回车事件
|
|
usernameInput.text_submitted.connect(_onUsernameSubmitted)
|
|
passwordInput.text_submitted.connect(_onPasswordSubmitted)
|
|
|
|
# 自动填充记住的账号密码
|
|
_loadSavedAccount()
|
|
|
|
# 初始化状态
|
|
_hideLoading()
|
|
_clearStatus()
|
|
_updateLoginMode()
|
|
|
|
## Tab切换 - 密码登录
|
|
func _onPasswordTabPressed() -> void:
|
|
if currentMode != LoginMode.PASSWORD:
|
|
currentMode = LoginMode.PASSWORD
|
|
codeLoginTab.button_pressed = false
|
|
passwordLoginTab.button_pressed = true
|
|
_updateLoginMode()
|
|
|
|
## Tab切换 - 验证码登录
|
|
func _onCodeTabPressed() -> void:
|
|
if currentMode != LoginMode.CODE:
|
|
currentMode = LoginMode.CODE
|
|
passwordLoginTab.button_pressed = false
|
|
codeLoginTab.button_pressed = true
|
|
_updateLoginMode()
|
|
|
|
## 更新登录模式UI
|
|
func _updateLoginMode() -> void:
|
|
match currentMode:
|
|
LoginMode.PASSWORD:
|
|
passwordInput.placeholder_text = "输入密码"
|
|
passwordInput.secret = true
|
|
togglePasswordButton.visible = true
|
|
LoginMode.CODE:
|
|
passwordInput.placeholder_text = "输入验证码"
|
|
passwordInput.secret = false
|
|
togglePasswordButton.visible = false
|
|
|
|
## 切换密码显示/隐藏
|
|
func _onTogglePasswordPressed() -> void:
|
|
passwordInput.secret = !passwordInput.secret
|
|
togglePasswordButton.text = "👁" if passwordInput.secret else "🔒"
|
|
|
|
## 加载保存的账号密码
|
|
func _loadSavedAccount() -> void:
|
|
var savedAccount = StorageService.loadAccount()
|
|
|
|
var username = savedAccount.get("username", "")
|
|
var password = savedAccount.get("password", "")
|
|
var rememberPassword = savedAccount.get("remember_password", false)
|
|
|
|
# 设置用户名
|
|
usernameInput.text = username
|
|
|
|
if rememberPassword and not password.is_empty():
|
|
passwordInput.text = password
|
|
rememberPasswordCheckBox.button_pressed = true
|
|
else:
|
|
rememberPasswordCheckBox.button_pressed = false
|
|
|
|
## 进入小镇按钮点击事件
|
|
func _onEnterButtonPressed() -> void:
|
|
match currentMode:
|
|
LoginMode.PASSWORD:
|
|
_handlePasswordLogin()
|
|
LoginMode.CODE:
|
|
_handleCodeLogin()
|
|
|
|
## 处理密码登录
|
|
func _handlePasswordLogin() -> void:
|
|
# 验证输入
|
|
var validation = _validateInput()
|
|
if not validation.valid:
|
|
_showError(validation.error_code)
|
|
return
|
|
|
|
# 显示加载状态
|
|
_showLoading("登录中...")
|
|
|
|
# 获取输入
|
|
var username = usernameInput.text.strip_edges()
|
|
var password = passwordInput.text
|
|
var remember = rememberPasswordCheckBox.button_pressed
|
|
|
|
# 调用 AuthManager 登录
|
|
var result = await AuthManager.login(username, password, remember)
|
|
|
|
# 隐藏加载状态
|
|
_hideLoading()
|
|
|
|
## 处理验证码登录
|
|
func _handleCodeLogin() -> void:
|
|
# TODO: 实现验证码登录逻辑
|
|
_showError(ErrorCode.SERVER_ERROR, "验证码登录功能暂未开放")
|
|
|
|
## 用户名输入框回车事件
|
|
func _onUsernameSubmitted(_text: String) -> void:
|
|
passwordInput.grab_focus()
|
|
|
|
## 密码输入框回车事件
|
|
func _onPasswordSubmitted(_text: String) -> void:
|
|
_onEnterButtonPressed()
|
|
|
|
## 忘记密码按钮点击
|
|
func _onForgotPasswordPressed() -> void:
|
|
# TODO: 跳转到忘记密码页面
|
|
_showError(ErrorCode.SERVER_ERROR, "忘记密码功能暂未开放")
|
|
|
|
## 注册按钮点击
|
|
func _onRegisterPressed() -> void:
|
|
# TODO: 跳转到注册页面
|
|
_showError(ErrorCode.SERVER_ERROR, "注册功能暂未开放")
|
|
|
|
## 登录成功回调
|
|
func _onLoginSuccess(userData: UserData) -> void:
|
|
_hideLoading()
|
|
_showSuccess("登录成功!")
|
|
|
|
# 延迟0.5秒后跳转到主菜单
|
|
await get_tree().create_timer(0.5).timeout
|
|
get_tree().change_scene_to_file("res://scenes/main_menu_scene.tscn")
|
|
|
|
## 登录失败回调
|
|
func _onLoginFailed(errorCode: int, errorMessage: String) -> void:
|
|
_hideLoading()
|
|
_showError(errorCode, errorMessage)
|
|
|
|
## 验证输入
|
|
func _validateInput() -> Dictionary:
|
|
var username = usernameInput.text.strip_edges()
|
|
var password = passwordInput.text
|
|
|
|
# 检查是否为空
|
|
if username.is_empty() or password.is_empty():
|
|
return {
|
|
"valid": false,
|
|
"error_code": ErrorCode.INVALID_INPUT
|
|
}
|
|
|
|
return {"valid": true}
|
|
|
|
## 显示加载状态
|
|
func _showLoading(message: String = "加载中...") -> void:
|
|
loadingLabel.text = message
|
|
loadingOverlay.visible = true
|
|
enterButton.disabled = true
|
|
|
|
## 隐藏加载状态
|
|
func _hideLoading() -> void:
|
|
loadingOverlay.visible = false
|
|
enterButton.disabled = false
|
|
|
|
## 显示错误提示
|
|
func _showError(errorCode: int, customMessage: String = "") -> void:
|
|
var message = customMessage if not customMessage.is_empty() else ErrorCode.getMessage(errorCode)
|
|
statusLabel.text = message
|
|
statusLabel.modulate = Color.RED
|
|
|
|
# 3秒后自动清除
|
|
await get_tree().create_timer(3.0).timeout
|
|
_clearStatus()
|
|
|
|
## 显示成功提示
|
|
func _showSuccess(message: String) -> void:
|
|
statusLabel.text = message
|
|
statusLabel.modulate = Color.GREEN
|
|
|
|
## 清除状态提示
|
|
func _clearStatus() -> void:
|
|
statusLabel.text = " "
|
|
statusLabel.modulate = Color.WHITE
|