import Foundation import ComposableArchitecture @Reducer struct EMailLoginFeature { @ObservableState struct State: Equatable { var email: String = "" var verificationCode: String = "" var isLoading: Bool = false var isCodeLoading: Bool = false var errorMessage: String? = nil var isCodeSent: Bool = false // 新增:登录流程状态 var loginStep: LoginStep = .initial enum LoginStep: Equatable { case initial case authenticating case completed case failed } init() { self.email = "" self.verificationCode = "" self.loginStep = .initial } } enum Action { case emailChanged(String) case verificationCodeChanged(String) case getVerificationCodeTapped case getCodeResponse(Result) case loginButtonTapped(email: String, verificationCode: String) case loginResponse(Result) case forgotPasswordTapped case resetState } @Dependency(\.apiService) var apiService var body: some ReducerOf { Reduce { state, action in switch action { case .emailChanged(let email): state.email = email state.errorMessage = nil return .none case .verificationCodeChanged(let code): state.verificationCode = code state.errorMessage = nil return .none case .getVerificationCodeTapped: guard !state.email.isEmpty else { state.errorMessage = LocalizedStringSync("email_login.email_required", comment: "") return .none } guard ValidationHelper.isValidEmail(state.email) else { state.errorMessage = LocalizedStringSync("email_login.invalid_email", comment: "") return .none } state.isCodeLoading = true state.isCodeSent = false // 重置状态确保触发变化 state.errorMessage = nil return .run { [email = state.email] send in do { guard let request = LoginHelper.createEmailGetCodeRequest(email: email) else { await send(.getCodeResponse(.failure(APIError.encryptionFailed))) return } let response = try await apiService.request(request) await send(.getCodeResponse(.success(response))) } catch { await send(.getCodeResponse(.failure(error))) } } case .getCodeResponse(.success(let response)): state.isCodeLoading = false if response.isSuccess { state.isCodeSent = true return .none } else { state.errorMessage = response.errorMessage return .none } case .getCodeResponse(.failure(let error)): state.isCodeLoading = false if let apiError = error as? APIError { state.errorMessage = apiError.localizedDescription } else { state.errorMessage = "验证码发送失败,请检查网络连接" } return .none case .loginButtonTapped(let email, let verificationCode): guard !email.isEmpty && !verificationCode.isEmpty else { state.errorMessage = LocalizedStringSync("email_login.fields_required", comment: "") return .none } guard ValidationHelper.isValidEmail(email) else { state.errorMessage = LocalizedStringSync("email_login.invalid_email", comment: "") return .none } state.isLoading = true state.errorMessage = nil state.loginStep = .authenticating return .run { send in do { guard let request = await LoginHelper.createEmailLoginRequest(email: email, code: verificationCode) else { await send(.loginResponse(.failure(APIError.encryptionFailed))) return } let response = try await apiService.request(request) if response.isSuccess, let loginData = response.data { guard let accountModel = AccountModel.from(loginData: loginData) else { await send(.loginResponse(.failure(APIError.invalidResponse))) return } // 第二阶段:获取Ticket let ticketRequest = TicketHelper.createTicketRequest( accessToken: accountModel.accessToken ?? "", uid: accountModel.uid.flatMap { Int($0) } ) let ticketResponse = try await apiService.request(ticketRequest) if ticketResponse.isSuccess, let ticket = ticketResponse.ticket { let completeAccount = accountModel.withTicket(ticket) await send(.loginResponse(.success(completeAccount))) } else { await send(.loginResponse(.failure(APIError.ticketFailed))) } } else { await send(.loginResponse(.failure(APIError.custom(response.errorMessage)))) } } catch { await send(.loginResponse(.failure(error))) } } case .loginResponse(.success(let accountModel)): state.isLoading = false state.loginStep = .completed // Effect 保存AccountModel并获取用户信息 return .run { _ in await UserInfoManager.saveAccountModel(accountModel) // 新增:登录成功后自动获取用户信息 debugInfoSync("🔄 邮箱登录成功,开始获取用户信息") if let _ = await UserInfoManager.fetchUserInfoFromServer( uid: accountModel.uid, apiService: apiService ) { debugInfoSync("✅ 用户信息获取成功") } else { debugErrorSync("❌ 用户信息获取失败,但不影响登录流程") } } case .loginResponse(.failure(let error)): state.isLoading = false state.loginStep = .failed if let apiError = error as? APIError { state.errorMessage = apiError.localizedDescription } else { state.errorMessage = "登录失败,请重试" } return .none case .forgotPasswordTapped: return .none case .resetState: state.email = "" state.verificationCode = "" state.isLoading = false state.isCodeLoading = false state.errorMessage = nil state.isCodeSent = false state.loginStep = .initial return .none } } } }