feat: 增强邮箱登录功能和密码恢复流程

- 更新邮箱登录相关功能,新增邮箱验证码获取和登录API端点。
- 添加AccountModel以管理用户认证信息,支持会话票据的存储和更新。
- 实现密码恢复功能,支持通过邮箱获取验证码和重置密码。
- 增加本地化支持,更新相关字符串以适应新功能。
- 引入ValidationHelper以验证邮箱和密码格式,确保用户输入的有效性。
- 更新视图以支持邮箱登录和密码恢复的用户交互。
This commit is contained in:
edwinQQQ
2025-07-10 14:00:58 +08:00
parent c470dba79c
commit e45ad3bad5
23 changed files with 2054 additions and 164 deletions

View File

@@ -11,13 +11,11 @@ struct IDLoginFeature {
var isLoading = false
var errorMessage: String?
// Ticket
var accessToken: String?
var ticket: String?
// Account Model Ticket
var accountModel: AccountModel?
var isTicketLoading = false
var ticketError: String?
var loginStep: LoginStep = .initial
var uid: Int? // uidInt
enum LoginStep: Equatable {
case initial //
@@ -101,22 +99,26 @@ struct IDLoginFeature {
if response.isSuccess {
// OAuth
state.errorMessage = nil
state.accessToken = response.data?.accessToken
state.uid = response.data?.uid // uid
//
if let userInfo = response.data?.userInfo {
UserInfoManager.saveUserInfo(userInfo)
}
print("✅ ID 登录 OAuth 认证成功")
if let accessToken = response.data?.accessToken {
print("🔑 Access Token: \(accessToken)")
// ticket uid
return .send(.requestTicket(accessToken: accessToken))
}
if let uid = response.data?.uid {
print("🆔 用户 UID: \(uid)")
// AccountModel
if let loginData = response.data,
let accountModel = AccountModel.from(loginData: loginData) {
state.accountModel = accountModel
//
if let userInfo = loginData.userInfo {
UserInfoManager.saveUserInfo(userInfo)
}
print("✅ ID 登录 OAuth 认证成功")
print("🔑 Access Token: \(accountModel.accessToken ?? "nil")")
print("🆔 用户 UID: \(accountModel.uid ?? "nil")")
// ticket
return .send(.requestTicket(accessToken: accountModel.accessToken!))
} else {
state.errorMessage = "登录数据格式错误"
state.loginStep = .failed
}
} else {
state.errorMessage = response.errorMessage
@@ -135,9 +137,10 @@ struct IDLoginFeature {
state.ticketError = nil
state.loginStep = .gettingTicket
return .run { [uid = state.uid] send in
return .run { [accountModel = state.accountModel] send in
do {
// 使 TicketHelper uid
// AccountModel uid Int
let uid = accountModel?.uid != nil ? Int(accountModel!.uid!) : nil
let ticketRequest = TicketHelper.createTicketRequest(accessToken: accessToken, uid: uid)
let response = try await apiService.request(ticketRequest)
await send(.ticketResponse(.success(response)))
@@ -151,27 +154,32 @@ struct IDLoginFeature {
state.isTicketLoading = false
if response.isSuccess {
state.ticketError = nil
state.ticket = response.ticket
state.loginStep = .completed
print("✅ ID 登录完整流程成功")
print("🎫 Ticket 获取成功: \(response.ticket ?? "nil")")
//
if let accessToken = state.accessToken,
let ticket = response.ticket {
//
let userInfo = UserInfoManager.getUserInfo()
UserInfoManager.saveCompleteAuthenticationData(
accessToken: accessToken,
ticket: ticket,
uid: state.uid,
userInfo: userInfo
)
// AccountModel ticket
if let ticket = response.ticket {
if var accountModel = state.accountModel {
accountModel.ticket = ticket
state.accountModel = accountModel
// AccountModel
UserInfoManager.saveAccountModel(accountModel)
// Ticket
NotificationCenter.default.post(name: .ticketSuccess, object: nil)
} else {
print("❌ AccountModel 不存在,无法保存 ticket")
state.ticketError = "内部错误:账户信息丢失"
state.loginStep = .failed
}
} else {
state.ticketError = "Ticket 为空"
state.loginStep = .failed
}
// TODO:
} else {
state.ticketError = response.errorMessage
state.loginStep = .failed
@@ -194,9 +202,7 @@ struct IDLoginFeature {
state.isTicketLoading = false
state.errorMessage = nil
state.ticketError = nil
state.accessToken = nil
state.ticket = nil
state.uid = nil // uid
state.accountModel = nil // AccountModel
state.loginStep = .initial
//