feat: 更新登录模块以支持验证码和渐变背景
主要变更: 1. 在 EPLoginTypesViewController 中添加了渐变背景到 actionButton,提升视觉效果。 2. 实现了输入框状态检查功能,确保在输入有效信息时启用登录按钮。 3. 更新了输入框配置,支持不同类型的键盘输入(如数字键盘和邮箱键盘)。 4. 在 EPLoginService 中添加了对手机号和邮箱的 DES 加密,增强安全性。 5. 更新了 EPLoginConfig,统一输入框和按钮的样式设置。 此更新旨在提升用户体验,确保登录过程的安全性和流畅性。
This commit is contained in:
@@ -27,6 +27,8 @@ class EPLoginTypesViewController: UIViewController {
|
||||
private let actionButton = UIButton(type: .system)
|
||||
private var forgotPasswordButton: UIButton?
|
||||
|
||||
private var hasAddedGradient = false
|
||||
|
||||
// MARK: - Lifecycle
|
||||
|
||||
override func viewDidLoad() {
|
||||
@@ -40,6 +42,24 @@ class EPLoginTypesViewController: UIViewController {
|
||||
navigationController?.setNavigationBarHidden(true, animated: animated)
|
||||
}
|
||||
|
||||
override func viewDidLayoutSubviews() {
|
||||
super.viewDidLayoutSubviews()
|
||||
|
||||
// 添加渐变背景到 actionButton(只添加一次)
|
||||
if !hasAddedGradient && actionButton.bounds.width > 0 {
|
||||
actionButton.addGradientBackground(
|
||||
with: [
|
||||
EPLoginConfig.Colors.gradientStart,
|
||||
EPLoginConfig.Colors.gradientEnd
|
||||
],
|
||||
start: CGPoint(x: 0, y: 0.5),
|
||||
end: CGPoint(x: 1, y: 0.5),
|
||||
cornerRadius: EPLoginConfig.Layout.uniformCornerRadius
|
||||
)
|
||||
hasAddedGradient = true
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Setup
|
||||
|
||||
private func setupUI() {
|
||||
@@ -89,17 +109,16 @@ class EPLoginTypesViewController: UIViewController {
|
||||
view.addSubview(secondInputView)
|
||||
|
||||
firstInputView.snp.makeConstraints { make in
|
||||
make.centerX.equalToSuperview()
|
||||
make.leading.equalToSuperview().offset(EPLoginConfig.Layout.uniformHorizontalPadding)
|
||||
make.trailing.equalToSuperview().offset(-EPLoginConfig.Layout.uniformHorizontalPadding)
|
||||
make.top.equalTo(titleLabel.snp.bottom).offset(EPLoginConfig.Layout.inputTitleSpacing)
|
||||
make.width.equalTo(EPLoginConfig.Layout.buttonWidth)
|
||||
make.height.equalTo(EPLoginConfig.Layout.buttonHeight)
|
||||
make.height.equalTo(EPLoginConfig.Layout.uniformHeight)
|
||||
}
|
||||
|
||||
secondInputView.snp.makeConstraints { make in
|
||||
make.centerX.equalToSuperview()
|
||||
make.leading.trailing.equalTo(firstInputView)
|
||||
make.top.equalTo(firstInputView.snp.bottom).offset(EPLoginConfig.Layout.inputVerticalSpacing)
|
||||
make.width.equalTo(EPLoginConfig.Layout.buttonWidth)
|
||||
make.height.equalTo(EPLoginConfig.Layout.buttonHeight)
|
||||
make.height.equalTo(EPLoginConfig.Layout.uniformHeight)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -107,16 +126,18 @@ class EPLoginTypesViewController: UIViewController {
|
||||
view.addSubview(actionButton)
|
||||
actionButton.setTitle("Login", for: .normal)
|
||||
actionButton.setTitleColor(EPLoginConfig.Colors.textLight, for: .normal)
|
||||
actionButton.backgroundColor = EPLoginConfig.Colors.primary
|
||||
actionButton.layer.cornerRadius = EPLoginConfig.Layout.cornerRadius
|
||||
actionButton.layer.cornerRadius = EPLoginConfig.Layout.uniformCornerRadius
|
||||
actionButton.titleLabel?.font = .systemFont(ofSize: EPLoginConfig.Layout.buttonFontSize, weight: .semibold)
|
||||
actionButton.addTarget(self, action: #selector(handleAction), for: .touchUpInside)
|
||||
|
||||
// 初始状态:禁用按钮
|
||||
actionButton.isEnabled = false
|
||||
actionButton.alpha = 0.5
|
||||
|
||||
actionButton.snp.makeConstraints { make in
|
||||
make.centerX.equalToSuperview()
|
||||
make.leading.trailing.equalTo(firstInputView)
|
||||
make.top.equalTo(secondInputView.snp.bottom).offset(EPLoginConfig.Layout.buttonTopSpacing)
|
||||
make.width.equalTo(EPLoginConfig.Layout.buttonWidth)
|
||||
make.height.equalTo(EPLoginConfig.Layout.buttonHeight)
|
||||
make.height.equalTo(EPLoginConfig.Layout.uniformHeight)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -130,16 +151,26 @@ class EPLoginTypesViewController: UIViewController {
|
||||
showAreaCode: false,
|
||||
showCodeButton: false,
|
||||
isSecure: false,
|
||||
icon: "person",
|
||||
placeholder: "Please enter ID"
|
||||
icon: "icon_login_id",
|
||||
placeholder: "Please enter ID",
|
||||
keyboardType: .numberPad // ID 使用数字键盘
|
||||
))
|
||||
firstInputView.onTextChanged = { [weak self] _ in
|
||||
self?.checkActionButtonStatus()
|
||||
}
|
||||
|
||||
secondInputView.configure(with: EPLoginInputConfig(
|
||||
showAreaCode: false,
|
||||
showCodeButton: false,
|
||||
isSecure: true,
|
||||
icon: "lock",
|
||||
placeholder: "Please enter password"
|
||||
icon: "icon_login_id",
|
||||
placeholder: "Please enter password",
|
||||
keyboardType: .default // 密码使用默认键盘(需要字母+数字)
|
||||
))
|
||||
secondInputView.onTextChanged = { [weak self] _ in
|
||||
self?.checkActionButtonStatus()
|
||||
}
|
||||
|
||||
actionButton.setTitle("Login", for: .normal)
|
||||
|
||||
// 添加忘记密码按钮
|
||||
@@ -152,15 +183,24 @@ class EPLoginTypesViewController: UIViewController {
|
||||
showCodeButton: false,
|
||||
isSecure: false,
|
||||
icon: "envelope",
|
||||
placeholder: "Please enter email"
|
||||
placeholder: "Please enter email",
|
||||
keyboardType: .emailAddress // Email 使用邮箱键盘
|
||||
))
|
||||
firstInputView.onTextChanged = { [weak self] _ in
|
||||
self?.checkActionButtonStatus()
|
||||
}
|
||||
|
||||
secondInputView.configure(with: EPLoginInputConfig(
|
||||
showAreaCode: false,
|
||||
showCodeButton: true,
|
||||
isSecure: false,
|
||||
icon: "number",
|
||||
placeholder: "Please enter verification code"
|
||||
placeholder: "Please enter verification code",
|
||||
keyboardType: .numberPad // 验证码使用数字键盘
|
||||
))
|
||||
secondInputView.onTextChanged = { [weak self] _ in
|
||||
self?.checkActionButtonStatus()
|
||||
}
|
||||
secondInputView.delegate = self
|
||||
actionButton.setTitle("Login", for: .normal)
|
||||
|
||||
@@ -171,15 +211,24 @@ class EPLoginTypesViewController: UIViewController {
|
||||
showCodeButton: false,
|
||||
isSecure: false,
|
||||
icon: "phone",
|
||||
placeholder: "Please enter phone"
|
||||
placeholder: "Please enter phone",
|
||||
keyboardType: .numberPad // 手机号使用数字键盘
|
||||
))
|
||||
firstInputView.onTextChanged = { [weak self] _ in
|
||||
self?.checkActionButtonStatus()
|
||||
}
|
||||
|
||||
secondInputView.configure(with: EPLoginInputConfig(
|
||||
showAreaCode: false,
|
||||
showCodeButton: true,
|
||||
isSecure: false,
|
||||
icon: "number",
|
||||
placeholder: "Please enter verification code"
|
||||
placeholder: "Please enter verification code",
|
||||
keyboardType: .numberPad // 验证码使用数字键盘
|
||||
))
|
||||
secondInputView.onTextChanged = { [weak self] _ in
|
||||
self?.checkActionButtonStatus()
|
||||
}
|
||||
secondInputView.delegate = self
|
||||
actionButton.setTitle("Login", for: .normal)
|
||||
|
||||
@@ -190,15 +239,24 @@ class EPLoginTypesViewController: UIViewController {
|
||||
showCodeButton: false,
|
||||
isSecure: false,
|
||||
icon: "envelope",
|
||||
placeholder: "Please enter email"
|
||||
placeholder: "Please enter email",
|
||||
keyboardType: .emailAddress // Email 使用邮箱键盘
|
||||
))
|
||||
firstInputView.onTextChanged = { [weak self] _ in
|
||||
self?.checkActionButtonStatus()
|
||||
}
|
||||
|
||||
secondInputView.configure(with: EPLoginInputConfig(
|
||||
showAreaCode: false,
|
||||
showCodeButton: true,
|
||||
isSecure: false,
|
||||
icon: "number",
|
||||
placeholder: "Please enter verification code"
|
||||
placeholder: "Please enter verification code",
|
||||
keyboardType: .numberPad // 验证码使用数字键盘
|
||||
))
|
||||
secondInputView.onTextChanged = { [weak self] _ in
|
||||
self?.checkActionButtonStatus()
|
||||
}
|
||||
secondInputView.delegate = self
|
||||
|
||||
// 添加第三个输入框
|
||||
@@ -212,15 +270,24 @@ class EPLoginTypesViewController: UIViewController {
|
||||
showCodeButton: false,
|
||||
isSecure: false,
|
||||
icon: "phone",
|
||||
placeholder: "Please enter phone"
|
||||
placeholder: "Please enter phone",
|
||||
keyboardType: .numberPad // 手机号使用数字键盘
|
||||
))
|
||||
firstInputView.onTextChanged = { [weak self] _ in
|
||||
self?.checkActionButtonStatus()
|
||||
}
|
||||
|
||||
secondInputView.configure(with: EPLoginInputConfig(
|
||||
showAreaCode: false,
|
||||
showCodeButton: true,
|
||||
isSecure: false,
|
||||
icon: "number",
|
||||
placeholder: "Please enter verification code"
|
||||
placeholder: "Please enter verification code",
|
||||
keyboardType: .numberPad // 验证码使用数字键盘
|
||||
))
|
||||
secondInputView.onTextChanged = { [weak self] _ in
|
||||
self?.checkActionButtonStatus()
|
||||
}
|
||||
secondInputView.delegate = self
|
||||
|
||||
// 添加第三个输入框
|
||||
@@ -253,23 +320,25 @@ class EPLoginTypesViewController: UIViewController {
|
||||
showCodeButton: false,
|
||||
isSecure: true,
|
||||
icon: EPLoginConfig.Images.iconLock,
|
||||
placeholder: "6-16 Digits + English Letters"
|
||||
placeholder: "6-16 Digits + English Letters",
|
||||
keyboardType: .default // 密码使用默认键盘(需要字母+数字)
|
||||
))
|
||||
inputView.onTextChanged = { [weak self] _ in
|
||||
self?.checkActionButtonStatus()
|
||||
}
|
||||
view.addSubview(inputView)
|
||||
|
||||
inputView.snp.makeConstraints { make in
|
||||
make.centerX.equalToSuperview()
|
||||
make.leading.trailing.equalTo(firstInputView)
|
||||
make.top.equalTo(secondInputView.snp.bottom).offset(EPLoginConfig.Layout.inputVerticalSpacing)
|
||||
make.width.equalTo(EPLoginConfig.Layout.buttonWidth)
|
||||
make.height.equalTo(EPLoginConfig.Layout.buttonHeight)
|
||||
make.height.equalTo(EPLoginConfig.Layout.uniformHeight)
|
||||
}
|
||||
|
||||
// 重新调整 actionButton 位置
|
||||
actionButton.snp.remakeConstraints { make in
|
||||
make.centerX.equalToSuperview()
|
||||
make.leading.trailing.equalTo(firstInputView)
|
||||
make.top.equalTo(inputView.snp.bottom).offset(EPLoginConfig.Layout.buttonTopSpacing)
|
||||
make.width.equalTo(EPLoginConfig.Layout.buttonWidth)
|
||||
make.height.equalTo(EPLoginConfig.Layout.buttonHeight)
|
||||
make.height.equalTo(EPLoginConfig.Layout.uniformHeight)
|
||||
}
|
||||
|
||||
thirdInputView = inputView
|
||||
@@ -513,16 +582,21 @@ class EPLoginTypesViewController: UIViewController {
|
||||
return
|
||||
}
|
||||
|
||||
let type = (displayType == .phoneReset) ? 2 : 1 // 2=找回密码, 1=登录
|
||||
|
||||
loginService.sendPhoneCode(phone: phone, areaCode: "+86", type: type) { [weak self] in
|
||||
DispatchQueue.main.async {
|
||||
self?.secondInputView.startCountdown()
|
||||
self?.showAlert("验证码已发送")
|
||||
}
|
||||
} failure: { [weak self] (code: Int, msg: String) in
|
||||
DispatchQueue.main.async {
|
||||
self?.showAlert("发送失败: \(msg)")
|
||||
// 检查是否需要人机验证
|
||||
loadCaptchaWebView { [weak self] in
|
||||
guard let self = self else { return }
|
||||
|
||||
let type = (self.displayType == .phoneReset) ? 2 : 1 // 2=找回密码, 1=登录
|
||||
|
||||
self.loginService.sendPhoneCode(phone: phone, areaCode: "+86", type: type) { [weak self] in
|
||||
DispatchQueue.main.async {
|
||||
self?.secondInputView.startCountdown()
|
||||
self?.showAlert("验证码已发送")
|
||||
}
|
||||
} failure: { [weak self] (code: Int, msg: String) in
|
||||
DispatchQueue.main.async {
|
||||
self?.showAlert("发送失败: \(msg)")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -538,8 +612,9 @@ class EPLoginTypesViewController: UIViewController {
|
||||
// MARK: - UI Helpers
|
||||
|
||||
private func showLoading(_ show: Bool) {
|
||||
actionButton.isEnabled = !show
|
||||
if show {
|
||||
actionButton.isEnabled = false
|
||||
actionButton.alpha = 0.5
|
||||
actionButton.setTitle("Loading...", for: .normal)
|
||||
} else {
|
||||
switch displayType {
|
||||
@@ -548,9 +623,36 @@ class EPLoginTypesViewController: UIViewController {
|
||||
case .emailReset, .phoneReset:
|
||||
actionButton.setTitle("Confirm", for: .normal)
|
||||
}
|
||||
checkActionButtonStatus()
|
||||
}
|
||||
}
|
||||
|
||||
/// 检查并更新按钮启用状态
|
||||
private func checkActionButtonStatus() {
|
||||
let isEnabled: Bool
|
||||
|
||||
switch displayType {
|
||||
case .id:
|
||||
let hasId = !firstInputView.text.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty
|
||||
let hasPassword = !secondInputView.text.isEmpty
|
||||
isEnabled = hasId && hasPassword
|
||||
|
||||
case .email, .phone:
|
||||
let hasAccount = !firstInputView.text.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty
|
||||
let hasCode = !secondInputView.text.isEmpty
|
||||
isEnabled = hasAccount && hasCode
|
||||
|
||||
case .emailReset, .phoneReset:
|
||||
let hasAccount = !firstInputView.text.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty
|
||||
let hasCode = !secondInputView.text.isEmpty
|
||||
let hasPassword = !(thirdInputView?.text.isEmpty ?? true)
|
||||
isEnabled = hasAccount && hasCode && hasPassword
|
||||
}
|
||||
|
||||
actionButton.isEnabled = isEnabled
|
||||
actionButton.alpha = isEnabled ? 1.0 : 0.5
|
||||
}
|
||||
|
||||
private func showAlert(_ message: String, completion: (() -> Void)? = nil) {
|
||||
let alert = UIAlertController(title: nil, message: message, preferredStyle: .alert)
|
||||
alert.addAction(UIAlertAction(title: "确定", style: .default) { _ in
|
||||
@@ -558,6 +660,37 @@ class EPLoginTypesViewController: UIViewController {
|
||||
})
|
||||
present(alert, animated: true)
|
||||
}
|
||||
|
||||
/// 加载人机验证 Captcha WebView
|
||||
/// - Parameter completion: 验证成功后的回调
|
||||
private func loadCaptchaWebView(completion: @escaping () -> Void) {
|
||||
guard ClientConfig.share().shouldDisplayCaptcha else {
|
||||
// 不需要验证,直接执行
|
||||
completion()
|
||||
return
|
||||
}
|
||||
|
||||
view.endEditing(true)
|
||||
|
||||
let webVC = XPWebViewController(roomUID: nil)
|
||||
webVC.view.frame = CGRect(x: 0, y: 0, width: UIScreen.main.bounds.width * 0.8, height: UIScreen.main.bounds.width * 1.2)
|
||||
webVC.view.backgroundColor = .clear
|
||||
webVC.view.layer.cornerRadius = 12
|
||||
webVC.view.layer.masksToBounds = true
|
||||
webVC.isLoginStatus = false
|
||||
webVC.isPush = false
|
||||
webVC.hideNavigationBar()
|
||||
webVC.url = URLWithType(.captchaSwitch)
|
||||
|
||||
webVC.verifyCaptcha = { result in
|
||||
if result {
|
||||
TTPopup.dismiss()
|
||||
completion()
|
||||
}
|
||||
}
|
||||
|
||||
TTPopup.popupView(webVC.view, style: .alert)
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - EPLoginInputViewDelegate
|
||||
|
@@ -33,18 +33,18 @@ import UIKit
|
||||
|
||||
override func viewDidLoad() {
|
||||
super.viewDidLoad()
|
||||
navigationController?.setNavigationBarHidden(true, animated: false)
|
||||
setupUI()
|
||||
loadPolicyStatus()
|
||||
}
|
||||
|
||||
override func viewWillAppear(_ animated: Bool) {
|
||||
super.viewWillAppear(animated)
|
||||
navigationController?.setNavigationBarHidden(true, animated: animated)
|
||||
|
||||
}
|
||||
|
||||
override func viewWillDisappear(_ animated: Bool) {
|
||||
super.viewWillDisappear(animated)
|
||||
// navigationController?.setNavigationBarHidden(false, animated: animated)
|
||||
}
|
||||
|
||||
// MARK: - Setup
|
||||
|
@@ -18,3 +18,16 @@ func YMLocalizedString(_ key: String) -> String {
|
||||
return Bundle.ymLocalizedString(forKey: key)
|
||||
}
|
||||
|
||||
/// 桥接 URLType 枚举常量
|
||||
extension URLType {
|
||||
static var captchaSwitch: URLType {
|
||||
return URLType(rawValue: 113)! // kCaptchaSwitchPath
|
||||
}
|
||||
}
|
||||
|
||||
/// DES 加密辅助函数
|
||||
func encryptDES(_ plainText: String) -> String {
|
||||
// 直接使用加密密钥(与 ObjC 版本保持一致)
|
||||
let key = "1ea53d260ecf11e7b56e00163e046a26"
|
||||
return DESEncrypt.encryptUseDES(plainText, key: key) ?? plainText
|
||||
}
|
||||
|
@@ -24,6 +24,13 @@ struct EPLoginConfig {
|
||||
static let loginButtonSpacing: CGFloat = 24
|
||||
/// 登录按钮左右边距
|
||||
static let loginButtonHorizontalPadding: CGFloat = 30
|
||||
|
||||
/// 输入框/按钮统一高度
|
||||
static let uniformHeight: CGFloat = 56
|
||||
/// 输入框/按钮统一左右边距
|
||||
static let uniformHorizontalPadding: CGFloat = 29
|
||||
/// 输入框/按钮统一圆角
|
||||
static let uniformCornerRadius: CGFloat = 28
|
||||
/// 标准圆角半径(按钮/输入框)
|
||||
static let cornerRadius: CGFloat = 23
|
||||
|
||||
@@ -83,13 +90,15 @@ struct EPLoginConfig {
|
||||
static let feedbackButtonCornerRadius: CGFloat = 10.5
|
||||
|
||||
/// 输入框高度
|
||||
static let inputHeight: CGFloat = 52
|
||||
static let inputHeight: CGFloat = 56
|
||||
/// 输入框圆角
|
||||
static let inputCornerRadius: CGFloat = 26
|
||||
static let inputCornerRadius: CGFloat = 28
|
||||
/// 输入框左右内边距
|
||||
static let inputHorizontalPadding: CGFloat = 24
|
||||
/// 输入框 icon 尺寸
|
||||
static let inputIconSize: CGFloat = 20
|
||||
/// 输入框边框宽度
|
||||
static let inputBorderWidth: CGFloat = 1
|
||||
|
||||
/// 验证码按钮宽度
|
||||
static let codeButtonWidth: CGFloat = 102
|
||||
@@ -117,11 +126,15 @@ struct EPLoginConfig {
|
||||
static let iconDisabled = UIColor.gray
|
||||
|
||||
/// 输入框颜色
|
||||
static let inputBackground = UIColor(red: 0xF3/255.0, green: 0xF5/255.0, blue: 0xFA/255.0, alpha: 1.0)
|
||||
static let inputBackground = UIColor.white.withAlphaComponent(0.1)
|
||||
static let inputText = UIColor(red: 0x1F/255.0, green: 0x1B/255.0, blue: 0x4F/255.0, alpha: 1.0)
|
||||
static let inputBorder = UIColor.lightGray.withAlphaComponent(0.3)
|
||||
static let inputBorder = UIColor.white
|
||||
static let inputBorderFocused = UIColor.systemPurple
|
||||
|
||||
/// 渐变色(Login/Confirm按钮)
|
||||
static let gradientStart = UIColor(red: 0xF8/255.0, green: 0x54/255.0, blue: 0xFC/255.0, alpha: 1.0) // #F854FC
|
||||
static let gradientEnd = UIColor(red: 0x50/255.0, green: 0x0F/255.0, blue: 0xFF/255.0, alpha: 1.0) // #500FFF
|
||||
|
||||
/// 验证码按钮颜色
|
||||
static let codeButtonBackground = UIColor(red: 0x91/255.0, green: 0x68/255.0, blue: 0xFA/255.0, alpha: 1.0)
|
||||
|
||||
@@ -203,11 +216,11 @@ struct EPLoginConfig {
|
||||
/// Client Secret
|
||||
static let clientSecret = "uyzjdhds"
|
||||
/// Client ID
|
||||
static let clientId = "1"
|
||||
static let clientId = "erban-client"
|
||||
/// Grant Type
|
||||
static let grantType = "sms_code"
|
||||
static let grantType = "password"
|
||||
/// 版本号
|
||||
static let version = "1.0.31"
|
||||
static let version = "1"
|
||||
|
||||
/// 验证码类型:登录
|
||||
static let codeTypeLogin = 1
|
||||
@@ -253,6 +266,10 @@ struct EPLoginConfig {
|
||||
/// 图标 - 数字
|
||||
static let iconNumber = "number"
|
||||
|
||||
/// 密码可见性图标
|
||||
static let iconPasswordSee = "icon_password_see"
|
||||
static let iconPasswordUnsee = "icon_password_unsee"
|
||||
|
||||
/// 图标 - 返回
|
||||
static let iconBack = "chevron.left"
|
||||
/// 图标 - 眼睛(隐藏)
|
||||
|
@@ -83,13 +83,16 @@ import Foundation
|
||||
completion: @escaping () -> Void,
|
||||
failure: @escaping (Int, String) -> Void) {
|
||||
|
||||
// 🔐 DES 加密邮箱
|
||||
let encryptedEmail = encryptDES(email)
|
||||
|
||||
Api.emailGetCode({ (data, code, msg) in
|
||||
if code == 200 {
|
||||
completion()
|
||||
} else {
|
||||
failure(Int(code), msg ?? "发送邮箱验证码失败")
|
||||
}
|
||||
}, emailAddress: email, type: NSNumber(value: type))
|
||||
}, emailAddress: encryptedEmail, type: NSNumber(value: type))
|
||||
}
|
||||
|
||||
/// 发送手机验证码
|
||||
@@ -105,10 +108,16 @@ import Foundation
|
||||
completion: @escaping () -> Void,
|
||||
failure: @escaping (Int, String) -> Void) {
|
||||
|
||||
// 注意:这里需要根据实际的 Api+Login 接口调用
|
||||
// 当前 Api+Login.h 中没有直接的手机验证码接口,可能需要通过其他方式
|
||||
print("[EPLoginService] sendPhoneCode - 需要确认实际的 API 接口")
|
||||
failure(-1, "手机验证码接口待确认")
|
||||
// 🔐 DES 加密手机号
|
||||
let encryptedPhone = encryptDES(phone)
|
||||
|
||||
Api.phoneSmsCode({ (data, code, msg) in
|
||||
if code == 200 {
|
||||
completion()
|
||||
} else {
|
||||
failure(Int(code), msg ?? "发送手机验证码失败")
|
||||
}
|
||||
}, mobile: encryptedPhone, type: String(type), phoneAreaCode: areaCode)
|
||||
}
|
||||
|
||||
// MARK: - Login Methods
|
||||
@@ -124,6 +133,10 @@ import Foundation
|
||||
completion: @escaping (AccountModel) -> Void,
|
||||
failure: @escaping (Int, String) -> Void) {
|
||||
|
||||
// 🔐 DES 加密 ID 和密码
|
||||
let encryptedId = encryptDES(id)
|
||||
let encryptedPassword = encryptDES(password)
|
||||
|
||||
Api.login(password: { [weak self] (data, code, msg) in
|
||||
self?.parseAndSaveAccount(
|
||||
data: data,
|
||||
@@ -133,8 +146,8 @@ import Foundation
|
||||
failure(errorCode, msg ?? "登录失败")
|
||||
})
|
||||
},
|
||||
phone: id,
|
||||
password: password,
|
||||
phone: encryptedId,
|
||||
password: encryptedPassword,
|
||||
client_secret: clientSecret,
|
||||
version: version,
|
||||
client_id: clientId,
|
||||
@@ -152,6 +165,9 @@ import Foundation
|
||||
completion: @escaping (AccountModel) -> Void,
|
||||
failure: @escaping (Int, String) -> Void) {
|
||||
|
||||
// 🔐 DES 加密邮箱
|
||||
let encryptedEmail = encryptDES(email)
|
||||
|
||||
Api.login(code: { [weak self] (data, code, msg) in
|
||||
self?.parseAndSaveAccount(
|
||||
data: data,
|
||||
@@ -161,7 +177,7 @@ import Foundation
|
||||
failure(errorCode, msg ?? "登录失败")
|
||||
})
|
||||
},
|
||||
email: email,
|
||||
email: encryptedEmail,
|
||||
code: code,
|
||||
client_secret: clientSecret,
|
||||
version: version,
|
||||
@@ -182,6 +198,9 @@ import Foundation
|
||||
completion: @escaping (AccountModel) -> Void,
|
||||
failure: @escaping (Int, String) -> Void) {
|
||||
|
||||
// 🔐 DES 加密手机号
|
||||
let encryptedPhone = encryptDES(phone)
|
||||
|
||||
Api.login(code: { [weak self] (data, code, msg) in
|
||||
self?.parseAndSaveAccount(
|
||||
data: data,
|
||||
@@ -191,7 +210,7 @@ import Foundation
|
||||
failure(errorCode, msg ?? "登录失败")
|
||||
})
|
||||
},
|
||||
phone: phone,
|
||||
phone: encryptedPhone,
|
||||
code: code,
|
||||
client_secret: clientSecret,
|
||||
version: version,
|
||||
@@ -215,13 +234,17 @@ import Foundation
|
||||
completion: @escaping () -> Void,
|
||||
failure: @escaping (Int, String) -> Void) {
|
||||
|
||||
// 🔐 DES 加密邮箱和新密码
|
||||
let encryptedEmail = encryptDES(email)
|
||||
let encryptedPassword = encryptDES(newPassword)
|
||||
|
||||
Api.resetPassword(email: { (data, code, msg) in
|
||||
if code == 200 {
|
||||
completion()
|
||||
} else {
|
||||
failure(Int(code), msg ?? "重置密码失败")
|
||||
}
|
||||
}, email: email, newPwd: newPassword, code: code)
|
||||
}, email: encryptedEmail, newPwd: encryptedPassword, code: code)
|
||||
}
|
||||
|
||||
/// 手机号重置密码
|
||||
@@ -239,13 +262,17 @@ import Foundation
|
||||
completion: @escaping () -> Void,
|
||||
failure: @escaping (Int, String) -> Void) {
|
||||
|
||||
// 🔐 DES 加密手机号和新密码
|
||||
let encryptedPhone = encryptDES(phone)
|
||||
let encryptedPassword = encryptDES(newPassword)
|
||||
|
||||
Api.resetPassword(phone: { (data, code, msg) in
|
||||
if code == 200 {
|
||||
completion()
|
||||
} else {
|
||||
failure(Int(code), msg ?? "重置密码失败")
|
||||
}
|
||||
}, phone: phone, newPwd: newPassword, smsCode: code, phoneAreaCode: areaCode)
|
||||
}, phone: encryptedPhone, newPwd: encryptedPassword, smsCode: code, phoneAreaCode: areaCode)
|
||||
}
|
||||
|
||||
// MARK: - Phone Quick Login (保留接口)
|
||||
|
@@ -16,6 +16,7 @@ struct EPLoginInputConfig {
|
||||
var isSecure: Bool = false
|
||||
var icon: String?
|
||||
var placeholder: String
|
||||
var keyboardType: UIKeyboardType = .default
|
||||
}
|
||||
|
||||
/// 输入框代理
|
||||
@@ -31,6 +32,9 @@ class EPLoginInputView: UIView {
|
||||
|
||||
weak var delegate: EPLoginInputViewDelegate?
|
||||
|
||||
/// 输入内容变化回调
|
||||
var onTextChanged: ((String) -> Void)?
|
||||
|
||||
private let stackView = UIStackView()
|
||||
|
||||
// 区号区域
|
||||
@@ -82,6 +86,8 @@ class EPLoginInputView: UIView {
|
||||
private func setupUI() {
|
||||
backgroundColor = EPLoginConfig.Colors.inputBackground
|
||||
layer.cornerRadius = EPLoginConfig.Layout.inputCornerRadius
|
||||
layer.borderWidth = EPLoginConfig.Layout.inputBorderWidth
|
||||
layer.borderColor = EPLoginConfig.Colors.inputBorder.cgColor
|
||||
|
||||
// Main StackView
|
||||
stackView.axis = .horizontal
|
||||
@@ -161,9 +167,10 @@ class EPLoginInputView: UIView {
|
||||
}
|
||||
|
||||
// TextField
|
||||
inputTextField.textColor = EPLoginConfig.Colors.inputText
|
||||
inputTextField.textColor = EPLoginConfig.Colors.textLight
|
||||
inputTextField.font = .systemFont(ofSize: 14)
|
||||
inputTextField.tintColor = EPLoginConfig.Colors.primary
|
||||
inputTextField.tintColor = EPLoginConfig.Colors.textLight
|
||||
inputTextField.addTarget(self, action: #selector(textFieldDidChange), for: .editingChanged)
|
||||
stackView.addArrangedSubview(inputTextField)
|
||||
|
||||
inputTextField.snp.makeConstraints { make in
|
||||
@@ -171,15 +178,18 @@ class EPLoginInputView: UIView {
|
||||
}
|
||||
}
|
||||
|
||||
@objc private func textFieldDidChange() {
|
||||
onTextChanged?(inputTextField.text ?? "")
|
||||
}
|
||||
|
||||
private func setupEyeButton() {
|
||||
eyeButton.setImage(UIImage(systemName: "eye.slash"), for: .normal)
|
||||
eyeButton.setImage(UIImage(systemName: "eye"), for: .selected)
|
||||
eyeButton.tintColor = EPLoginConfig.Colors.icon
|
||||
eyeButton.setImage(kImage(EPLoginConfig.Images.iconPasswordUnsee), for: .normal)
|
||||
eyeButton.setImage(kImage(EPLoginConfig.Images.iconPasswordSee), for: .selected)
|
||||
eyeButton.addTarget(self, action: #selector(handleEyeTap), for: .touchUpInside)
|
||||
stackView.addArrangedSubview(eyeButton)
|
||||
|
||||
eyeButton.snp.makeConstraints { make in
|
||||
make.width.equalTo(30)
|
||||
make.size.equalTo(24)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -209,16 +219,17 @@ class EPLoginInputView: UIView {
|
||||
// 区号
|
||||
areaStackView.isHidden = !config.showAreaCode
|
||||
|
||||
// Icon
|
||||
if let iconName = config.icon {
|
||||
iconImageView.image = UIImage(systemName: iconName)
|
||||
iconImageView.isHidden = false
|
||||
} else {
|
||||
iconImageView.isHidden = true
|
||||
}
|
||||
// Icon - 默认隐藏,不再使用
|
||||
iconImageView.isHidden = true
|
||||
|
||||
// Placeholder
|
||||
inputTextField.placeholder = config.placeholder
|
||||
// Placeholder(60% 白色)
|
||||
inputTextField.attributedPlaceholder = NSAttributedString(
|
||||
string: config.placeholder,
|
||||
attributes: [NSAttributedString.Key.foregroundColor: UIColor.white.withAlphaComponent(0.6)]
|
||||
)
|
||||
|
||||
// 键盘类型
|
||||
inputTextField.keyboardType = config.keyboardType
|
||||
|
||||
// 密码模式
|
||||
inputTextField.isSecureTextEntry = config.isSecure
|
||||
|
@@ -28,8 +28,8 @@
|
||||
/// @param phone 手机号
|
||||
/// @param password 验证码
|
||||
+ (void)loginWithPassword:(HttpRequestHelperCompletion)completion phone:(NSString *)phone password:(NSString *)password client_secret:(NSString *)client_secret version:(NSString *)version client_id:(NSString *)client_id grant_type:(NSString *)grant_type {
|
||||
NSString * fang = [NSString stringFromBase64String:@"b2F1dGgvdG9rZW4="];///oauth/token
|
||||
[self makeRequest:fang method:HttpRequestHelperMethodPOST completion:completion, __FUNCTION__,phone,password,client_secret,version, client_id, grant_type, nil];
|
||||
|
||||
[self makeRequest:@"oauth/token" method:HttpRequestHelperMethodPOST completion:completion, __FUNCTION__,phone,password,client_secret,version, client_id, grant_type, nil];
|
||||
}
|
||||
|
||||
/// 重置手机号登录密码
|
||||
|
@@ -43,6 +43,7 @@
|
||||
// MARK: - Utilities
|
||||
#import "UIImage+Utils.h"
|
||||
#import "NSString+Utils.h"
|
||||
#import "UIView+GradientLayer.h"
|
||||
#import <MJExtension/MJExtension.h>
|
||||
|
||||
// MARK: - Login - Navigation & Web
|
||||
@@ -51,6 +52,9 @@
|
||||
|
||||
// MARK: - Login - Utilities
|
||||
#import "YUMIMacroUitls.h" // YMLocalizedString
|
||||
#import "YUMIHtmlUrl.h" // URLWithType
|
||||
#import "YUMIConstant.h" // KeyWithType, KeyType_PasswordEncode
|
||||
#import "DESEncrypt.h" // DES加密工具
|
||||
|
||||
// MARK: - Login - Models (Phase 2 使用,先添加)
|
||||
#import "AccountInfoStorage.h"
|
||||
@@ -60,6 +64,10 @@
|
||||
#import "Api+Login.h"
|
||||
#import "Api+Main.h"
|
||||
|
||||
// MARK: - Login - Captcha & Config
|
||||
#import "ClientConfig.h"
|
||||
#import "TTPopup.h"
|
||||
|
||||
// 注意:
|
||||
// 1. EPMomentViewController 和 EPMineViewController 直接继承 UIViewController
|
||||
// 2. 不继承 BaseViewController(避免 ClientConfig → PIBaseModel 依赖链)
|
||||
|
Reference in New Issue
Block a user