
- 在DynamicsModels.swift中新增MyMomentInfo结构,专门用于处理/dynamic/getMyDynamic接口的响应数据。 - 更新MyMomentsResponse结构以使用MyMomentInfo,确保数据类型一致性。 - 在LoginModels.swift中重构IDLoginAPIRequest和EmailLoginRequest,优化queryParameters的实现方式,提升代码可读性。 - 在RecoverPasswordFeature中重构ResetPasswordRequest,优化queryParameters的实现方式,确保一致性。 - 在多个视图中添加调试信息,增强调试能力和用户体验。 - 更新Localizable.strings文件,新增动态列表为空时的提示信息,提升用户交互体验。
293 lines
11 KiB
Swift
293 lines
11 KiB
Swift
import Foundation
|
||
import ComposableArchitecture
|
||
|
||
@Reducer
|
||
struct RecoverPasswordFeature {
|
||
@ObservableState
|
||
struct State: Equatable {
|
||
var email: String = ""
|
||
var verificationCode: String = ""
|
||
var newPassword: String = ""
|
||
var isCodeLoading: Bool = false
|
||
var isResetLoading: Bool = false
|
||
var isResetSuccess: Bool = false
|
||
var errorMessage: String? = nil
|
||
var isCodeSent: Bool = false
|
||
|
||
#if DEBUG
|
||
init() {
|
||
self.email = "exzero@126.com"
|
||
self.verificationCode = ""
|
||
self.newPassword = ""
|
||
}
|
||
#endif
|
||
}
|
||
|
||
enum Action {
|
||
case emailChanged(String)
|
||
case verificationCodeChanged(String)
|
||
case newPasswordChanged(String)
|
||
case getVerificationCodeTapped
|
||
case getCodeResponse(Result<EmailGetCodeResponse, Error>)
|
||
case resetPasswordTapped
|
||
case resetPasswordResponse(Result<ResetPasswordResponse, Error>)
|
||
case resetSuccess
|
||
case resetState
|
||
}
|
||
|
||
@Dependency(\.apiService) var apiService
|
||
|
||
var body: some ReducerOf<Self> {
|
||
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 .newPasswordChanged(let password):
|
||
state.newPassword = password
|
||
state.errorMessage = nil
|
||
return .none
|
||
|
||
case .getVerificationCodeTapped:
|
||
guard !state.email.isEmpty else {
|
||
state.errorMessage = LocalizedStringSync("recover_password.email_required", comment: "")
|
||
return .none
|
||
}
|
||
|
||
guard ValidationHelper.isValidEmail(state.email) else {
|
||
state.errorMessage = LocalizedStringSync("recover_password.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 = RecoverPasswordHelper.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 = LocalizedStringSync("recover_password.code_send_failed", comment: "")
|
||
}
|
||
return .none
|
||
|
||
case .resetPasswordTapped:
|
||
guard !state.email.isEmpty && !state.verificationCode.isEmpty && !state.newPassword.isEmpty else {
|
||
state.errorMessage = LocalizedStringSync("recover_password.fields_required", comment: "")
|
||
return .none
|
||
}
|
||
|
||
guard ValidationHelper.isValidEmail(state.email) else {
|
||
state.errorMessage = LocalizedStringSync("recover_password.invalid_email", comment: "")
|
||
return .none
|
||
}
|
||
|
||
guard ValidationHelper.isValidPassword(state.newPassword) else {
|
||
state.errorMessage = LocalizedStringSync("recover_password.invalid_password", comment: "")
|
||
return .none
|
||
}
|
||
|
||
state.isResetLoading = true
|
||
state.errorMessage = nil
|
||
|
||
return .run { [email = state.email, code = state.verificationCode, password = state.newPassword] send in
|
||
do {
|
||
guard let request = RecoverPasswordHelper.createResetPasswordRequest(
|
||
email: email,
|
||
code: code,
|
||
newPassword: password
|
||
) else {
|
||
await send(.resetPasswordResponse(.failure(APIError.encryptionFailed)))
|
||
return
|
||
}
|
||
|
||
let response = try await apiService.request(request)
|
||
await send(.resetPasswordResponse(.success(response)))
|
||
|
||
} catch {
|
||
await send(.resetPasswordResponse(.failure(error)))
|
||
}
|
||
}
|
||
|
||
case .resetPasswordResponse(.success(let response)):
|
||
state.isResetLoading = false
|
||
|
||
if response.isSuccess {
|
||
state.isResetSuccess = true
|
||
state.errorMessage = nil
|
||
return .send(.resetSuccess)
|
||
} else {
|
||
state.errorMessage = response.errorMessage
|
||
return .none
|
||
}
|
||
|
||
case .resetPasswordResponse(.failure(let error)):
|
||
state.isResetLoading = false
|
||
if let apiError = error as? APIError {
|
||
state.errorMessage = apiError.localizedDescription
|
||
} else {
|
||
state.errorMessage = LocalizedStringSync("recover_password.reset_failed", comment: "")
|
||
}
|
||
return .none
|
||
|
||
case .resetSuccess:
|
||
// 密码重置成功,准备返回上一页
|
||
return .none
|
||
|
||
case .resetState:
|
||
state.email = ""
|
||
state.verificationCode = ""
|
||
state.newPassword = ""
|
||
state.isCodeLoading = false
|
||
state.isResetLoading = false
|
||
state.isResetSuccess = false
|
||
state.errorMessage = nil
|
||
state.isCodeSent = false
|
||
return .none
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
// MARK: - Password Reset API Models
|
||
|
||
/// 密码重置响应模型
|
||
struct ResetPasswordResponse: Codable, Equatable {
|
||
let status: String?
|
||
let message: String?
|
||
let code: Int?
|
||
let data: String?
|
||
|
||
/// 是否重置成功
|
||
var isSuccess: Bool {
|
||
return code == 200 || status?.lowercased() == "success"
|
||
}
|
||
|
||
/// 错误消息(如果有)
|
||
var errorMessage: String {
|
||
return message ?? LocalizedStringSync("recover_password.reset_failed", comment: "")
|
||
}
|
||
}
|
||
|
||
/// 密码重置请求 - 新API端点
|
||
struct ResetPasswordRequest: APIRequestProtocol {
|
||
typealias Response = ResetPasswordResponse
|
||
|
||
let endpoint = "/acc/pwd/resetByEmail" // 新的API端点
|
||
let method: HTTPMethod = .POST
|
||
let includeBaseParameters = true
|
||
var bodyParameters: [String: Any]? { nil }
|
||
let timeout: TimeInterval = 30.0
|
||
|
||
// MARK: - Private Properties
|
||
private let email: String
|
||
private let code: String
|
||
private let newPwd: String
|
||
|
||
// MARK: - Computed Properties
|
||
var queryParameters: [String: String]? {
|
||
return [
|
||
"email": email,
|
||
"newPwd": newPwd, // 参数名改为newPwd
|
||
"code": code
|
||
]
|
||
}
|
||
|
||
/// 初始化密码重置请求
|
||
/// - Parameters:
|
||
/// - email: DES加密后的邮箱地址
|
||
/// - code: 验证码
|
||
/// - newPwd: DES加密后的新密码
|
||
init(email: String, code: String, newPwd: String) {
|
||
self.email = email
|
||
self.code = code
|
||
self.newPwd = newPwd
|
||
}
|
||
}
|
||
|
||
// MARK: - Recover Password Helper
|
||
struct RecoverPasswordHelper {
|
||
|
||
/// 创建邮箱验证码获取请求(复用邮箱登录的实现)
|
||
/// - Parameter email: 原始邮箱地址
|
||
/// - Returns: 配置好的API请求,如果加密失败返回nil
|
||
static func createEmailGetCodeRequest(email: String) -> EmailGetCodeRequest? {
|
||
let encryptionKey = "1ea53d260ecf11e7b56e00163e046a26"
|
||
|
||
guard let encryptedEmail = DESEncrypt.encryptUseDES(email, key: encryptionKey) else {
|
||
debugErrorSync("❌ 邮箱DES加密失败")
|
||
return nil
|
||
}
|
||
|
||
debugInfoSync("🔐 密码恢复邮箱DES加密成功")
|
||
debugInfoSync(" 原始邮箱: \(email)")
|
||
debugInfoSync(" 加密邮箱: \(encryptedEmail)")
|
||
|
||
// 使用type=3表示密码重置验证码
|
||
return EmailGetCodeRequest(emailAddress: email, type: 3)
|
||
}
|
||
|
||
/// 创建密码重置请求
|
||
/// - Parameters:
|
||
/// - email: 原始邮箱地址
|
||
/// - code: 验证码
|
||
/// - newPassword: 新密码
|
||
/// - Returns: 配置好的API请求,如果加密失败返回nil
|
||
static func createResetPasswordRequest(email: String, code: String, newPassword: String) -> ResetPasswordRequest? {
|
||
let encryptionKey = "1ea53d260ecf11e7b56e00163e046a26"
|
||
|
||
guard let encryptedEmail = DESEncrypt.encryptUseDES(email, key: encryptionKey),
|
||
let encryptedPassword = DESEncrypt.encryptUseDES(newPassword, key: encryptionKey) else {
|
||
debugErrorSync("❌ 密码重置DES加密失败")
|
||
return nil
|
||
}
|
||
|
||
debugInfoSync("🔐 密码重置DES加密成功")
|
||
debugInfoSync(" 原始邮箱: \(email)")
|
||
debugInfoSync(" 加密邮箱: \(encryptedEmail)")
|
||
debugInfoSync(" 验证码: \(code)")
|
||
debugInfoSync(" 原始新密码: \(newPassword)")
|
||
debugInfoSync(" 加密新密码: \(encryptedPassword)")
|
||
|
||
return ResetPasswordRequest(
|
||
email: email,
|
||
code: code,
|
||
newPwd: encryptedPassword // 参数名改为newPwd
|
||
)
|
||
}
|
||
}
|