| | |
| | | 134A453A2C6E167D00538D78 /* CourseOfficalCommendTopCCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = 134A45382C6E167D00538D78 /* CourseOfficalCommendTopCCell.xib */; }; |
| | | 134CC7E02C73283700EAEFB7 /* PavilionSearchVC.xib in Resources */ = {isa = PBXBuildFile; fileRef = 134CC7DF2C73283700EAEFB7 /* PavilionSearchVC.xib */; }; |
| | | 134CC7E12C73283700EAEFB7 /* PavilionSearchVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = 134CC7DE2C73283700EAEFB7 /* PavilionSearchVC.swift */; }; |
| | | 135B1D202C8863D10089A9BE /* Types.swift in Sources */ = {isa = PBXBuildFile; fileRef = 135B1D1F2C8863D10089A9BE /* Types.swift */; }; |
| | | 135B1D222C8868170089A9BE /* Models.swift in Sources */ = {isa = PBXBuildFile; fileRef = 135B1D212C8868170089A9BE /* Models.swift */; }; |
| | | 135B1D252C8947630089A9BE /* UserViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 135B1D242C8947630089A9BE /* UserViewModel.swift */; }; |
| | | 135C2A502C7EC48D00CC2A67 /* apngb-animated_sun.png in Resources */ = {isa = PBXBuildFile; fileRef = 135C2A4F2C7EC48D00CC2A67 /* apngb-animated_sun.png */; }; |
| | | 135C2A652C7F033300CC2A67 /* CLAnimationTransitioning.swift in Sources */ = {isa = PBXBuildFile; fileRef = 135C2A512C7F033300CC2A67 /* CLAnimationTransitioning.swift */; }; |
| | | 135C2A662C7F033300CC2A67 /* CLFullScreenController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 135C2A522C7F033300CC2A67 /* CLFullScreenController.swift */; }; |
| | |
| | | 134A45382C6E167D00538D78 /* CourseOfficalCommendTopCCell.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = CourseOfficalCommendTopCCell.xib; sourceTree = "<group>"; }; |
| | | 134CC7DE2C73283700EAEFB7 /* PavilionSearchVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PavilionSearchVC.swift; sourceTree = "<group>"; }; |
| | | 134CC7DF2C73283700EAEFB7 /* PavilionSearchVC.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = PavilionSearchVC.xib; sourceTree = "<group>"; }; |
| | | 135B1D1F2C8863D10089A9BE /* Types.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Types.swift; sourceTree = "<group>"; }; |
| | | 135B1D212C8868170089A9BE /* Models.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Models.swift; sourceTree = "<group>"; }; |
| | | 135B1D242C8947630089A9BE /* UserViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserViewModel.swift; sourceTree = "<group>"; }; |
| | | 135C2A4F2C7EC48D00CC2A67 /* apngb-animated_sun.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "apngb-animated_sun.png"; sourceTree = "<group>"; }; |
| | | 135C2A512C7F033300CC2A67 /* CLAnimationTransitioning.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CLAnimationTransitioning.swift; sourceTree = "<group>"; }; |
| | | 135C2A522C7F033300CC2A67 /* CLFullScreenController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CLFullScreenController.swift; sourceTree = "<group>"; }; |
| | |
| | | path = VC; |
| | | sourceTree = "<group>"; |
| | | }; |
| | | 135B1D232C8947570089A9BE /* ViewModels */ = { |
| | | isa = PBXGroup; |
| | | children = ( |
| | | 135B1D242C8947630089A9BE /* UserViewModel.swift */, |
| | | ); |
| | | path = ViewModels; |
| | | sourceTree = "<group>"; |
| | | }; |
| | | 135C2A552C7F033300CC2A67 /* CLFullScreenController */ = { |
| | | isa = PBXGroup; |
| | | children = ( |
| | |
| | | 1385DFFF2C6C4F1200AADB1F /* Network */ = { |
| | | isa = PBXGroup; |
| | | children = ( |
| | | 135B1D232C8947570089A9BE /* ViewModels */, |
| | | 1385DFFB2C6C4F1200AADB1F /* NetworkRequest.swift */, |
| | | 1385DFFD2C6C4F1200AADB1F /* Services.swift */, |
| | | 135B1D212C8868170089A9BE /* Models.swift */, |
| | | ); |
| | | path = Network; |
| | | sourceTree = "<group>"; |
| | |
| | | 13985DB42C69B7DF0046B6DC /* Def.swift */, |
| | | 13985DB72C69B80D0046B6DC /* Themes.swift */, |
| | | 13897D882C7DB9D7006209E0 /* EqualCellSpaceFlowLayout.swift */, |
| | | 135B1D1F2C8863D10089A9BE /* Types.swift */, |
| | | ); |
| | | path = Config; |
| | | sourceTree = "<group>"; |
| | |
| | | 13FB6D872C6EF9DE00A0685D /* CourseDetialVC.swift in Sources */, |
| | | 135C2A652C7F033300CC2A67 /* CLAnimationTransitioning.swift in Sources */, |
| | | 132DB8FE2C74826D00EF33A7 /* SettingVC.swift in Sources */, |
| | | 135B1D222C8868170089A9BE /* Models.swift in Sources */, |
| | | 135B1D202C8863D10089A9BE /* Types.swift in Sources */, |
| | | 135C2A662C7F033300CC2A67 /* CLFullScreenController.swift in Sources */, |
| | | 138F0C352C7597CA0072A16C /* HelpCenterVC.swift in Sources */, |
| | | 13D256B42C6C68E7006FC2D7 /* ShareView.swift in Sources */, |
| | |
| | | 135C2A752C7F033300CC2A67 /* CLPlayerView.swift in Sources */, |
| | | 1300BD3C2C6DFB1C000BCA5E /* VIPCenterVC.swift in Sources */, |
| | | 134803D62C76E3E000F4FDDA /* WatchHistoryVC.swift in Sources */, |
| | | 135B1D252C8947630089A9BE /* UserViewModel.swift in Sources */, |
| | | 1377B4162C6DCC4300CF7CA5 /* Home_Style_4_Inner_1_CCell.swift in Sources */, |
| | | 135C2A6D2C7F033300CC2A67 /* CLRotateAnimationView.swift in Sources */, |
| | | 13E160212C6CB8930027F781 /* CommentListVC.swift in Sources */, |
New file |
| | |
| | | { |
| | | "images" : [ |
| | | { |
| | | "idiom" : "universal", |
| | | "scale" : "1x" |
| | | }, |
| | | { |
| | | "filename" : "btn_eye_close@2x.png", |
| | | "idiom" : "universal", |
| | | "scale" : "2x" |
| | | }, |
| | | { |
| | | "filename" : "btn_eye_close@3x.png", |
| | | "idiom" : "universal", |
| | | "scale" : "3x" |
| | | } |
| | | ], |
| | | "info" : { |
| | | "author" : "xcode", |
| | | "version" : 1 |
| | | } |
| | | } |
New file |
| | |
| | | { |
| | | "images" : [ |
| | | { |
| | | "idiom" : "universal", |
| | | "scale" : "1x" |
| | | }, |
| | | { |
| | | "filename" : "icon_code@2x.png", |
| | | "idiom" : "universal", |
| | | "scale" : "2x" |
| | | }, |
| | | { |
| | | "filename" : "icon_code@3x.png", |
| | | "idiom" : "universal", |
| | | "scale" : "3x" |
| | | } |
| | | ], |
| | | "info" : { |
| | | "author" : "xcode", |
| | | "version" : 1 |
| | | } |
| | | } |
New file |
| | |
| | | { |
| | | "images" : [ |
| | | { |
| | | "idiom" : "universal", |
| | | "scale" : "1x" |
| | | }, |
| | | { |
| | | "filename" : "icon_fail@2x.png", |
| | | "idiom" : "universal", |
| | | "scale" : "2x" |
| | | }, |
| | | { |
| | | "filename" : "icon_fail@3x.png", |
| | | "idiom" : "universal", |
| | | "scale" : "3x" |
| | | } |
| | | ], |
| | | "info" : { |
| | | "author" : "xcode", |
| | | "version" : 1 |
| | | } |
| | | } |
New file |
| | |
| | | // |
| | | // Types.swift |
| | | // XQMuse |
| | | // |
| | | // Created by 无故事王国 on 2024/9/4. |
| | | // |
| | | |
| | | import Foundation |
| | | import HandyJSON |
| | | |
| | | enum LoginType{ |
| | | case pwd,code |
| | | } |
| | | |
| | | enum AgreementType:Int,HandyJSONEnum{ |
| | | case none = 0 |
| | | ///用户协议 |
| | | case user = 1 |
| | | ///隐私协议 |
| | | case privacy = 2 |
| | | /// 关于我们 |
| | | case aboutUs = 3 |
| | | /// 新手指南 |
| | | case guide = 4 |
| | | /// 课程/冥想 |
| | | case course = 5 |
| | | } |
| | | |
| | | |
| | | enum SendCodeType:Int,HandyJSONEnum{ |
| | | //注册 |
| | | case register = 1 |
| | | ///验证码登录 |
| | | case codeLogin = 2 |
| | | ///找回密码 |
| | | case forgetPwd = 3 |
| | | ///第三方登录后验证手机 |
| | | case threePlantform = 4 |
| | | } |
| | |
| | | |
| | | |
| | | class LoginViewModel{ |
| | | enum LoginType{ |
| | | case pwd,code |
| | | } |
| | | |
| | | var loginType = BehaviorRelay<LoginType>(value:.pwd) |
| | | var loginPhone = BehaviorRelay<String>(value:"") |
| | | var loginContent = BehaviorRelay<String>(value:"") |
| | |
| | | @IBOutlet weak var btn_register: UIButton! |
| | | @IBOutlet weak var btn_login: UIButton! |
| | | @IBOutlet weak var btn_sendCode: UIButton! |
| | | @IBOutlet weak var btn_isRead: UIButton! |
| | | |
| | | |
| | | private var viewModel = LoginViewModel() |
| | |
| | | } |
| | | |
| | | override func setUI() { |
| | | btn_eye.isSelected = true |
| | | view.addSubview(unlineImageView) |
| | | unlineImageView.snp.makeConstraints { make in |
| | | make.top.equalTo(self.btn_loginByPwd.snp.bottom).offset(6) |
| | |
| | | |
| | | @IBAction func loginTypeAction(_ sender: UIButton) { |
| | | sender.tag == 10 ? viewModel.loginType.accept(.pwd):viewModel.loginType.accept(.code) |
| | | |
| | | switch viewModel.loginType.value{ |
| | | case .code: |
| | | tf_content.isSecureTextEntry = false |
| | | case .pwd: |
| | | tf_content.isSecureTextEntry = btn_eye.isSelected |
| | | } |
| | | } |
| | | |
| | | @IBAction func eyeAction(_ sender: UIButton) { |
| | | sender.isSelected = !sender.isSelected |
| | | tf_content.isSecureTextEntry = sender.isSelected |
| | | } |
| | | |
| | | @IBAction func isReadAction(_ sender: UIButton) { |
| | | sender.isSelected = !sender.isSelected |
| | | } |
| | | |
| | | |
| | | @IBAction func sendCodeAction(_ sender: UIButton) { |
| | | |
| | | guard !viewModel.loginPhone.value.isEmpty else {alert(msg: "请输入手机号");return} |
| | | guard viewModel.loginPhone.value.jq_isPhone else {alert(msg: "请输入正确手机号");return} |
| | | |
| | | sender.jq_openCountDown(60, defultTitle: "发送验证码") { |
| | | sender.titleLabel?.font = UIFont.systemFont(ofSize: 12) |
| | | sender.setTitleColor(.black.withAlphaComponent(0.3), for: .normal) |
| | | } completeClouse: { |
| | | sender.titleLabel?.font = UIFont.systemFont(ofSize: 14, weight: .medium) |
| | | sender.setTitleColor(UIColor(hexStr: "#96AD81"), for: .normal) |
| | | } |
| | | Services.sendCode(type: .codeLogin).subscribe(onNext: {data in |
| | | if let _ = data.data{ |
| | | sender.jq_openCountDown(60, defultTitle: "发送验证码") { |
| | | sender.titleLabel?.font = UIFont.systemFont(ofSize: 12) |
| | | sender.setTitleColor(.black.withAlphaComponent(0.3), for: .normal) |
| | | } completeClouse: { |
| | | sender.titleLabel?.font = UIFont.systemFont(ofSize: 14, weight: .medium) |
| | | sender.setTitleColor(UIColor(hexStr: "#96AD81"), for: .normal) |
| | | } |
| | | } |
| | | }).disposed(by: disposeBag) |
| | | } |
| | | |
| | | @IBAction func loginAction(_ sender: UIButton) { |
| | | |
| | | guard viewModel.checkSafe() else {return} |
| | | guard btn_isRead.isSelected else { |
| | | alertError(msg: "请阅读并同意《用户注册协议》和《用户隐私协议》");return |
| | | } |
| | | |
| | | Services.loginBy(phone: viewModel.loginPhone.value, content: viewModel.loginContent.value, type: viewModel.loginType.value).subscribe(onNext: { data in |
| | | if let model = data.data{ |
| | | UserViewModel.saveUserInfo(model) |
| | | sceneDelegate?.loginSuccess() |
| | | } |
| | | }).disposed(by: disposeBag) |
| | | } |
| | | |
| | | @IBAction func userRegisterTreatyAction(_ sender: UIButton) { |
| | | let vc = LoginTreatyVC() |
| | | vc.topIndex = 0 |
| | | vc.clickHandle {[unowned self] state in |
| | | self.btn_isRead.isSelected = state |
| | | } |
| | | vc.modalPresentationStyle = .custom |
| | | present(vc, animated: true) |
| | | } |
| | | |
| | | @IBAction func userPrivateTreatyAction(_ sender: UIButton) { |
| | | let vc = LoginTreatyVC() |
| | | vc.topIndex = 1 |
| | | vc.clickHandle {[unowned self] state in |
| | | self.btn_isRead.isSelected = state |
| | | } |
| | | vc.modalPresentationStyle = .custom |
| | | present(vc, animated: true) |
| | | } |
| | |
| | | <placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner" customClass="LoginVC" customModule="XQMuse" customModuleProvider="target"> |
| | | <connections> |
| | | <outlet property="btn_eye" destination="3sh-AF-8OT" id="XFA-5f-8tu"/> |
| | | <outlet property="btn_isRead" destination="6Xe-Xr-eHg" id="2cB-qi-GNv"/> |
| | | <outlet property="btn_login" destination="eKb-oX-1Uq" id="dDh-bd-0Xq"/> |
| | | <outlet property="btn_loginByCode" destination="Afa-A3-2l1" id="E63-hJ-wVB"/> |
| | | <outlet property="btn_loginByPwd" destination="Ec8-sg-6R6" id="Y2P-aU-5lk"/> |
| | |
| | | </constraints> |
| | | <inset key="imageEdgeInsets" minX="0.0" minY="0.0" maxX="2.2250738585072014e-308" maxY="0.0"/> |
| | | <state key="normal" title="Button" image="btn_eye_open"/> |
| | | <state key="selected" image="btn_eye_close"/> |
| | | <connections> |
| | | <action selector="eyeAction:" destination="-1" eventType="touchUpInside" id="dWR-mX-Km9"/> |
| | | </connections> |
| | |
| | | <inset key="imageEdgeInsets" minX="0.0" minY="0.0" maxX="2.2250738585072014e-308" maxY="0.0"/> |
| | | <state key="normal" title="Button" image="btn_choose"/> |
| | | <state key="selected" image="btn_choose_s"/> |
| | | <connections> |
| | | <action selector="isReadAction:" destination="-1" eventType="touchUpInside" id="mKS-up-7fH"/> |
| | | </connections> |
| | | </button> |
| | | <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="我已阅读并同意" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="esZ-HR-QwQ"> |
| | | <rect key="frame" x="57" y="240" width="86" height="14.333333333333343"/> |
| | |
| | | <resources> |
| | | <image name="btn_choose" width="28" height="28"/> |
| | | <image name="btn_choose_s" width="28" height="28"/> |
| | | <image name="btn_eye_close" width="21" height="8"/> |
| | | <image name="btn_eye_open" width="20" height="20"/> |
| | | <image name="btn_loginApple" width="44" height="44"/> |
| | | <image name="btn_wechat" width="44" height="44"/> |
| | |
| | | |
| | | @IBOutlet weak var tf_input: QMUITextField! |
| | | @IBOutlet weak var btn_complete: UIButton! |
| | | @IBOutlet weak var btn_eye: UIButton! |
| | | private let shadowView = UIView() |
| | | var secretCode:String = "" |
| | | var phone:String = "" |
| | | |
| | | |
| | | init(phone:String,secretCode:String) { |
| | | super.init(nibName: nil, bundle: nil) |
| | | self.phone = phone |
| | | self.secretCode = secretCode |
| | | } |
| | | |
| | | required init?(coder: NSCoder) { |
| | | fatalError("init(coder:) has not been implemented") |
| | | } |
| | | |
| | | override func viewDidLoad() { |
| | | super.viewDidLoad() |
| | | title = "找回密码" |
| | | } |
| | | |
| | | override func setUI() { |
| | | btn_eye.isSelected = true |
| | | view.addSubview(shadowView) |
| | | shadowView.backgroundColor = .white |
| | | shadowView.snp.makeConstraints { make in |
| | |
| | | shadowView.jq_gradientColor(colorArr: [UIColor(hexStr: "#F5F5F5").withAlphaComponent(0.15).cgColor,UIColor.white.cgColor], cornerRadius: 0, startPoint: CGPoint(x: 0, y: 0), endPoint: CGPoint(x: 0, y: 1), bounds: CGRect(x: 0, y: 0, width: JQ_ScreenW, height: 30),locations: [0.1,0.9]) |
| | | |
| | | } |
| | | |
| | | @IBAction func eyeAction(_ sender: UIButton) { |
| | | btn_eye.isSelected = !btn_eye.isSelected |
| | | tf_input.isSecureTextEntry = btn_eye.isSelected |
| | | } |
| | | |
| | | @IBAction func completeAction(_ sender: UIButton) { |
| | | view.endEditing(true) |
| | | guard !tf_input.text!.isEmpty else {alertError(msg: "请输入密码");return} |
| | | guard tf_input.text!.count >= 8 else {alertError(msg: "密码至少8个字符,不能全是字母或数字");return} |
| | | guard tf_input.text!.jq_isComplexPassword else {alertError(msg: "密码至少8个字符,不能全是字母或数字");return} |
| | | view.endEditing(true) |
| | | Popup_1_View.show(state: .success, title: "修改成功", subtitle: "您的密码已修改成功,快去登录账户吧") { |
| | | self.navigationController?.popToRootViewController(animated: true) |
| | | } |
| | | |
| | | Services.updatePwd(cellPhone: phone, password: tf_input.text!, secretCode: secretCode).subscribe(onNext: {data in |
| | | if let model = data.data{ |
| | | Popup_1_View.show(state: .success, title: "修改成功", subtitle: "您的密码已修改成功,快去登录账户吧") { |
| | | self.navigationController?.popToRootViewController(animated: true) |
| | | } |
| | | } |
| | | }).disposed(by: disposeBag) |
| | | } |
| | | } |
| | |
| | | <placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner" customClass="ForgotPasswordChangeVC" customModule="XQMuse" customModuleProvider="target"> |
| | | <connections> |
| | | <outlet property="btn_complete" destination="d75-LE-ADF" id="rmq-Hs-zrm"/> |
| | | <outlet property="btn_eye" destination="Yms-9v-sdO" id="OUp-yM-n4g"/> |
| | | <outlet property="tf_input" destination="LM8-B2-jWF" id="sqd-EQ-r6O"/> |
| | | <outlet property="view" destination="i5M-Pr-FkT" id="sfx-zR-JGt"/> |
| | | </connections> |
| | |
| | | <rect key="frame" x="342" y="193.66666666666666" width="20" height="22"/> |
| | | <inset key="imageEdgeInsets" minX="0.0" minY="0.0" maxX="2.2250738585072014e-308" maxY="0.0"/> |
| | | <state key="normal" image="btn_eye_open"/> |
| | | <state key="selected" image="btn_eye_close"/> |
| | | <connections> |
| | | <action selector="eyeAction:" destination="-1" eventType="touchUpInside" id="i8H-qL-5Sc"/> |
| | | </connections> |
| | | </button> |
| | | <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="至少8个字符,不能全是字母或数字" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="XwG-d3-D1z"> |
| | | <rect key="frame" x="31" y="249.66666666666663" width="227" height="17"/> |
| | |
| | | </view> |
| | | </objects> |
| | | <resources> |
| | | <image name="btn_eye_close" width="21" height="8"/> |
| | | <image name="btn_eye_open" width="20" height="20"/> |
| | | <systemColor name="systemBackgroundColor"> |
| | | <color white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/> |
| | |
| | | super.viewDidAppear(animated) |
| | | c1.becomeFirstResponder() |
| | | c1.jq_borderWidth = 1 |
| | | starTimer() |
| | | sendCode() |
| | | } |
| | | |
| | | override func viewDidLoad() { |
| | |
| | | } |
| | | } |
| | | |
| | | |
| | | private func sendCode(){ |
| | | Services.sendCode(type: .forgetPwd).subscribe(onNext: { _ in |
| | | self.starTimer() |
| | | }).disposed(by: disposeBag) |
| | | } |
| | | |
| | | private func starTimer(){ |
| | | times = 60 |
| | | btn_retry.isEnabled = false |
| | |
| | | } |
| | | |
| | | @IBAction func checkingAction(_ sender: UIButton) { |
| | | view.endEditing(true) |
| | | if inputCode.count != 6{ |
| | | alertError(msg: "请输入验证码");return |
| | | } |
| | | view.endEditing(true) |
| | | Popup_1_View.show(state: .success, title: "验证成功", subtitle:"手机号验证成功") { |
| | | let vc = ForgotPasswordChangeVC() |
| | | self.push(vc: vc) |
| | | } |
| | | |
| | | Services.forgotPwdVerifyCode(cellPhone: phone, captcha: inputCode).subscribe(onNext: {data in |
| | | if data.data?.successFlag ?? false{ |
| | | Popup_1_View.show(state: .success, title: "验证成功", subtitle:"手机号验证成功") { |
| | | let vc = ForgotPasswordChangeVC(phone:self.phone,secretCode: data.data?.secret ?? "") |
| | | self.push(vc: vc) |
| | | } |
| | | }else{ |
| | | Popup_1_View.show(state: .fail, title: "验证失败", subtitle:"手机号验证失败") { |
| | | |
| | | } |
| | | } |
| | | }).disposed(by: disposeBag) |
| | | |
| | | } |
| | | |
| | | @IBAction func tryAgainAction(_ sender: UIButton) { |
| | | view.endEditing(true) |
| | | starTimer() |
| | | sendCode() |
| | | } |
| | | |
| | | |
| | |
| | | } |
| | | |
| | | @IBAction func checkingAction(_ sender: UIButton) { |
| | | view.endEditing(true) |
| | | if tf_phone.text!.isEmpty{ |
| | | alertError(msg: "请输入手机号");return |
| | | } |
| | |
| | | if !tf_phone.text!.jq_isPhone{ |
| | | alertError(msg: "请输入正确手机号");return |
| | | } |
| | | view.endEditing(true) |
| | | let vc = ForgotPasswordInputCodeVC(phone: tf_phone.text!) |
| | | push(vc: vc) |
| | | |
| | | } |
| | | |
| | | |
| | |
| | | class LoginTreatyVC: BaseVC { |
| | | @IBOutlet weak var view_menu: UIView! |
| | | @IBOutlet weak var view_content: UIView! |
| | | |
| | | var topIndex = 0 |
| | | |
| | | private(set) var pageMenu:SPPageMenu = { |
| | | let pageMenu = SPPageMenu(frame: .zero, trackerStyle: .line) |
| | | // 追踪线 |
| | |
| | | pageVC.scrollview.bounces = false |
| | | return pageVC |
| | | }() |
| | | private var clouse:((Bool)->Void)! |
| | | |
| | | override func viewWillAppear(_ animated: Bool) { |
| | | super.viewWillAppear(animated) |
| | | UIView.animate(withDuration: 0.5) { |
| | |
| | | override func viewDidLoad() { |
| | | super.viewDidLoad() |
| | | view.backgroundColor = UIColor.black.withAlphaComponent(0) |
| | | |
| | | DispatchQueue.main.asyncAfter(delay: 0.1) { |
| | | self.pageMenu.selectedItemIndex = self.topIndex |
| | | self.pageViewController.scroll(toPage: self.topIndex, animation: true) |
| | | } |
| | | } |
| | | |
| | | override func setUI() { |
| | | view_menu.addSubview(pageMenu) |
| | | pageMenu.delegate = self |
| | | pageMenu.snp.makeConstraints { make in |
| | | make.edges.equalToSuperview() |
| | | } |
| | |
| | | } |
| | | } |
| | | |
| | | func clickHandle(_ clouse:@escaping (Bool)->Void){ |
| | | self.clouse = clouse |
| | | } |
| | | |
| | | @IBAction func rejectAction(_ sender: UIButton) { |
| | | dismiss(animated: true) |
| | | clouse(false) |
| | | } |
| | | |
| | | @IBAction func completeAction(_ sender: UIButton) { |
| | | dismiss(animated: true) |
| | | clouse(true) |
| | | } |
| | | } |
| | | |
| | |
| | | } |
| | | |
| | | func pageViewController(_ pageViewConteoller: FFPageViewController, controllerForPage page: Int) -> UIViewController { |
| | | return WebVC(url: "https://www.baidu.com") |
| | | |
| | | var agreementType:AgreementType = .none |
| | | if page == 0{ |
| | | agreementType = .user |
| | | }else{ |
| | | agreementType = .privacy |
| | | } |
| | | |
| | | return WebVC(type: agreementType) |
| | | } |
| | | } |
| | |
| | | @IBOutlet weak var tf_pwd: QMUITextField! |
| | | @IBOutlet weak var tf_pwdAgain: QMUITextField! |
| | | @IBOutlet weak var btn_register: UIButton! |
| | | |
| | | @IBOutlet weak var btn_isRead: UIButton! |
| | | |
| | | private var viewModel = RegisterViewModel() |
| | | |
| | | let shadowView = UIView() |
| | |
| | | guard !viewModel.phone.value.isEmpty else {alertError(msg: "请输入手机号");return} |
| | | guard viewModel.phone.value.jq_isPhone else {alertError(msg: "请输入正确手机号");return} |
| | | |
| | | sender.jq_openCountDown(60, defultTitle: "发送验证码") { |
| | | sender.titleLabel?.font = UIFont.systemFont(ofSize: 12) |
| | | sender.setTitleColor(.black.withAlphaComponent(0.3), for: .normal) |
| | | } completeClouse: { |
| | | sender.titleLabel?.font = UIFont.systemFont(ofSize: 14, weight: .medium) |
| | | sender.setTitleColor(UIColor(hexStr: "#96AD81"), for: .normal) |
| | | } |
| | | Services.sendCode(type: .register).subscribe(onNext: {data in |
| | | if let _ = data.data{ |
| | | sender.jq_openCountDown(60, defultTitle: "发送验证码") { |
| | | sender.titleLabel?.font = UIFont.systemFont(ofSize: 12) |
| | | sender.setTitleColor(.black.withAlphaComponent(0.3), for: .normal) |
| | | } completeClouse: { |
| | | sender.titleLabel?.font = UIFont.systemFont(ofSize: 14, weight: .medium) |
| | | sender.setTitleColor(UIColor(hexStr: "#96AD81"), for: .normal) |
| | | } |
| | | } |
| | | }).disposed(by: disposeBag) |
| | | } |
| | | |
| | | @IBAction func registerAction(_ sender: UIButton) { |
| | | |
| | | guard viewModel.checkSafe() else {return} |
| | | view.endEditing(true) |
| | | guard viewModel.checkSafe() else {return} |
| | | guard btn_isRead.isSelected else { |
| | | alertError(msg: "请阅读并同意《用户注册协议》和《用户隐私协议》");return |
| | | } |
| | | |
| | | Services.register(cellPhone: viewModel.phone.value, captcha: viewModel.code.value, password: viewModel.pwd.value).subscribe(onNext: {data in |
| | | if let model = data.data{ |
| | | UserViewModel.saveUserInfo(model) |
| | | sceneDelegate?.loginSuccess() |
| | | } |
| | | }).disposed(by: disposeBag) |
| | | } |
| | | |
| | | @IBAction func isReadAction(_ sender: UIButton) { |
| | | sender.isSelected = !sender.isSelected |
| | | } |
| | | |
| | | |
| | | @IBAction func userResigerAgreementAction(_ sender: Any) { |
| | | let vc = WebVC() |
| | | let vc = WebVC(type: .user) |
| | | vc.title = "用户注册协议" |
| | | push(vc: vc) |
| | | } |
| | | |
| | | |
| | | @IBAction func userPrivateAgreementAction(_ sender: Any) { |
| | | let vc = WebVC() |
| | | let vc = WebVC(type: .privacy) |
| | | vc.title = "用户隐私协议" |
| | | push(vc: vc) |
| | | } |
| | |
| | | <objects> |
| | | <placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner" customClass="RegisterVC" customModule="XQMuse" customModuleProvider="target"> |
| | | <connections> |
| | | <outlet property="btn_isRead" destination="iO1-Hp-lde" id="ixe-V6-sXe"/> |
| | | <outlet property="btn_register" destination="PqN-MA-u63" id="odf-D6-k92"/> |
| | | <outlet property="tf_code" destination="vho-4t-8f7" id="iq1-yh-uY9"/> |
| | | <outlet property="tf_phone" destination="e5F-tB-S0k" id="nJI-hk-jml"/> |
| | |
| | | <inset key="imageEdgeInsets" minX="0.0" minY="0.0" maxX="2.2250738585072014e-308" maxY="0.0"/> |
| | | <state key="normal" title="Button" image="btn_choose"/> |
| | | <state key="selected" image="btn_choose_s"/> |
| | | <connections> |
| | | <action selector="isReadAction:" destination="-1" eventType="touchUpInside" id="KBs-ma-2YF"/> |
| | | </connections> |
| | | </button> |
| | | <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="我已阅读并同意" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="ioV-dr-25D"> |
| | | <rect key="frame" x="57" y="436" width="86" height="14.333333333333314"/> |
| | |
| | | |
| | | static func show(state:Popup_1_State,title:String,subtitle:String, complete:@escaping()->Void){ |
| | | let popupView = Popup_1_View.jq_loadNibView() |
| | | switch state { |
| | | case .fail: |
| | | popupView.img_state.image = UIImage(named: "icon_fail") |
| | | case .success: |
| | | popupView.img_state.image = UIImage(named: "icon_success") |
| | | } |
| | | popupView.label_title.text = title |
| | | popupView.label_subTitle.text = subtitle |
| | | popupView.completeClouse = complete |
New file |
| | |
| | | // |
| | | // Model.swift |
| | | // XQMuse |
| | | // |
| | | // Created by 无故事王国 on 2024/9/4. |
| | | // |
| | | |
| | | import HandyJSON |
| | | import UserDefaultsStore |
| | | |
| | | struct LoginUserInfoModel:HandyJSON,Identifiable,Codable{ |
| | | |
| | | static let idKey = \LoginUserInfoModel.userid |
| | | |
| | | var accessToken: String = "" |
| | | var appUserId: Int = 0 |
| | | var bindStatus: Int = 0 |
| | | var cellPhone: String = "" |
| | | var expireIn: Int = 0 |
| | | var expireTime: Int = 0 |
| | | var ipaddr: String = "" |
| | | var loginTime: Int = 0 |
| | | var token: String = "" |
| | | var userid: Int = 0 |
| | | var username: String = "" |
| | | } |
| | | |
| | | |
| | | struct HtmlModel:HandyJSON{ |
| | | var content: String = "" |
| | | var contentType:AgreementType = .none |
| | | var id: Int = 0 |
| | | } |
| | | |
| | | |
| | | struct VerifiyForgotPwdModel:HandyJSON{ |
| | | var secret:String = "" |
| | | var successFlag:Bool = false |
| | | } |
| | |
| | | struct SimpleModel: HandyJSON { |
| | | |
| | | } |
| | | struct HtmlModel: HandyJSON { |
| | | var content = "" |
| | | var content1 = "" |
| | | var id = 0 |
| | | var type = 0 |
| | | } |
| | | |
| | | extension String: HandyJSON{ |
| | | |
| | |
| | | /// 参数加密 |
| | | @discardableResult |
| | | func done() -> Parameters { |
| | | var paramsArray: [String] = [] |
| | | // 排序 |
| | | let sortedArray: [String] = Array(params.keys).sorted() |
| | | |
| | | //防止自签名而错误 |
| | | if !sortedArray.contains("sign"){ |
| | | for item in sortedArray{ |
| | | // 拼接字符串 |
| | | if params.has(key: item){ |
| | | paramsArray.append("\(item)=\(params[item]!)") |
| | | } |
| | | } |
| | | let content = paramsArray.joined(separator: "&") |
| | | // params += ["sign": "\(content.jq_hmacBase64(algorithm: .SHA1, key: SHAKEY))"] |
| | | |
| | | #if DEBUG |
| | | // LogInfo("签名:\(content) ----- \(content.jq_hmacBase64(algorithm: .SHA1, key: SHAKEY))") |
| | | #endif |
| | | } |
| | | // var paramsArray: [String] = [] |
| | | // // 排序 |
| | | // let sortedArray: [String] = Array(params.keys).sorted() |
| | | // |
| | | // //防止自签名而错误 |
| | | // if !sortedArray.contains("sign"){ |
| | | // for item in sortedArray{ |
| | | // // 拼接字符串 |
| | | // if params.has(key: item){ |
| | | // paramsArray.append("\(item)=\(params[item]!)") |
| | | // } |
| | | // } |
| | | // let content = paramsArray.joined(separator: "&") |
| | | // |
| | | //// params += ["sign": "\(content.jq_hmacBase64(algorithm: .SHA1, key: SHAKEY))"] |
| | | // |
| | | //#if DEBUG |
| | | //// LogInfo("签名:\(content) ----- \(content.jq_hmacBase64(algorithm: .SHA1, key: SHAKEY))") |
| | | //#endif |
| | | // } |
| | | return self.params |
| | | } |
| | | |
| | |
| | | import JQTools |
| | | |
| | | #if DEBUG |
| | | let All_Url = "http://" |
| | | let All_Url = "https://console-mock.apipost.cn/mock/edb6887b-40b2-4245-aab0-50d773033f15" |
| | | #else |
| | | let All_Url = "http://" //正式地址 |
| | | #endif |
| | |
| | | |
| | | } |
| | | |
| | | // MARK: -- 登录 |
| | | extension Services{ |
| | | |
| | | // class func updateInfo(birthday:String?,gender:Int?,name:String?)->Observable<BaseResponse<SimpleModel>>{ |
| | | // let params = ParamsAppender.build(url: All_Url) |
| | | // .interface(url: "/account/api/appUser/updateInfo") |
| | | // .append(key: "birthday", value: birthday) |
| | | // .append(key: "gender", value: gender) |
| | | // .append(key: "name", value: name) |
| | | // return NetworkRequest.request(params: params, method: .post, progress: false) |
| | | // } |
| | | /// 密码登录 |
| | | class func loginBy(phone:String,content:String,type:LoginType)->Observable<BaseResponse<LoginUserInfoModel>>{ |
| | | let params = ParamsAppender.build(url: All_Url) |
| | | |
| | | switch type { |
| | | case .pwd: |
| | | params.interface(url: "/auth/app/login") |
| | | .append(key: "cellPhone", value: phone) |
| | | .append(key: "password", value: content.jq_md5String().uppercased()) |
| | | case .code: |
| | | params.interface(url: "/auth/app/captchaLogin") |
| | | .append(key: "cellPhone", value: phone) |
| | | .append(key: "captcha",value:content) |
| | | } |
| | | return NetworkRequest.request(params: params, method: .post, progress: true) |
| | | } |
| | | |
| | | /// 发送验证码 |
| | | class func sendCode(type:SendCodeType)->Observable<BaseResponse<SimpleModel>>{ |
| | | let params = ParamsAppender.build(url: All_Url) |
| | | params.interface(url: "/auth/app/sendCaptchaCode") |
| | | .append(key: "type", value: type.rawValue) |
| | | return NetworkRequest.request(params: params, method: .get, progress: true) |
| | | } |
| | | |
| | | /// 注册 |
| | | class func register(cellPhone:String,captcha:String,inviteUserId:String? = nil,password:String)->Observable<BaseResponse<LoginUserInfoModel>>{ |
| | | let params = ParamsAppender.build(url: All_Url) |
| | | params.interface(url: "/auth/app/register") |
| | | .append(key: "cellPhone", value: cellPhone) |
| | | .append(key: "captcha", value: captcha) |
| | | .append(key: "inviteUserId", value: inviteUserId) |
| | | .append(key: "password", value: password.jq_md5String().uppercased()) |
| | | return NetworkRequest.request(params: params, method: .post, progress: true) |
| | | } |
| | | |
| | | /// 找回密码验证手机号 |
| | | class func forgotPwdVerifyCode(cellPhone:String,captcha:String)->Observable<BaseResponse<VerifiyForgotPwdModel>>{ |
| | | let params = ParamsAppender.build(url: All_Url) |
| | | params.interface(url: "/auth/app/verifyPhone") |
| | | .append(key: "cellPhone", value: cellPhone) |
| | | .append(key: "captcha", value: captcha) |
| | | return NetworkRequest.request(params: params, method: .post, progress: true) |
| | | } |
| | | |
| | | class func updatePwd(cellPhone:String,password:String,secretCode:String)->Observable<BaseResponse<SimpleModel>>{ |
| | | let params = ParamsAppender.build(url: All_Url) |
| | | params.interface(url: "/auth/app/changePassword") |
| | | .append(key: "cellPhone", value: cellPhone) |
| | | .append(key: "password", value: password.jq_md5String().uppercased()) |
| | | .append(key: "secret", value: secretCode) |
| | | return NetworkRequest.request(params: params, method: .post, progress: true) |
| | | } |
| | | } |
| | | |
| | | extension Services{ |
| | | /// 获取协议 |
| | | class func agreementBy(_ type:AgreementType)->Observable<BaseResponse<HtmlModel>>{ |
| | | let params = ParamsAppender.build(url: All_Url) |
| | | .interface(url: "/system/public/getContent") |
| | | .append(key: "key", value: type.rawValue) |
| | | return NetworkRequest.request(params: params, method: .get, progress: false) |
| | | } |
| | | |
| | | } |
New file |
| | |
| | | // |
| | | // UserViewModel.swift |
| | | // XQMuse |
| | | // |
| | | // Created by 无故事王国 on 2024/9/5. |
| | | // |
| | | |
| | | import Foundation |
| | | import UserDefaultsStore |
| | | |
| | | class UserViewModel{ |
| | | private static let userInfo = UserDefaultsStore<LoginUserInfoModel>(uniqueIdentifier: "UserInfoModel")! |
| | | |
| | | static func getToken()->String?{ |
| | | return UserDefaults.standard.object(forKey: "_userToken") as? String |
| | | } |
| | | static func saveToken(_ token:String){ |
| | | UserDefaults.standard.set(token, forKey: "_userToken") |
| | | UserDefaults.standard.synchronize() |
| | | } |
| | | |
| | | static func clearToken(){ |
| | | UserDefaults.standard.set(nil, forKey: "_userToken") |
| | | UserDefaults.standard.synchronize() |
| | | } |
| | | |
| | | static func saveUserInfo(_ model:LoginUserInfoModel){ |
| | | do{ |
| | | try UserViewModel.userInfo.save(model) |
| | | }catch{ |
| | | |
| | | } |
| | | } |
| | | |
| | | static func getUserInfo()->LoginUserInfoModel?{ |
| | | return UserViewModel.userInfo.allObjects().first |
| | | } |
| | | |
| | | static func clearUserInfo(){ |
| | | UserViewModel.userInfo.deleteAll() |
| | | } |
| | | } |
| | |
| | | |
| | | import UIKit |
| | | import WebKit |
| | | import JQTools |
| | | |
| | | class WebVC: BaseVC { |
| | | |
| | | private var webView:WKWebView? |
| | | private(set) var url = "" |
| | | private(set) var htmlText = "" |
| | | private var type:AgreementType? |
| | | private(set) var url:String? |
| | | private(set) var htmlText:String? |
| | | private(set) var baseUrl:URL? |
| | | private var progressView = UIProgressView() |
| | | private let jsCode = """ |
| | |
| | | public convenience init(url:String) { |
| | | self.init() |
| | | self.url = url |
| | | } |
| | | |
| | | public convenience init(type:AgreementType){ |
| | | self.init() |
| | | self.type = type |
| | | } |
| | | |
| | | public convenience init(htmlText:String,baseURL:URL? = nil) { |
| | |
| | | make.height.equalTo(2) |
| | | } |
| | | |
| | | if type != nil{ |
| | | Services.agreementBy(type!).subscribe(onNext: {data in |
| | | if let model = data.data{ |
| | | self.webView?.loadHTMLString(model.content.jq_wrapHtml(), baseURL: nil) |
| | | } |
| | | }).disposed(by: disposeBag) |
| | | } |
| | | |
| | | if !url.isEmpty { |
| | | let urlRequest = URLRequest(url: URL(string: url)!) |
| | | if url != nil { |
| | | let urlRequest = URLRequest(url: URL(string: url!)!) |
| | | webView?.load(urlRequest) |
| | | }else{ |
| | | webView?.loadHTMLString(htmlText, baseURL: baseUrl) |
| | | return |
| | | } |
| | | |
| | | if htmlText != nil{ |
| | | webView?.loadHTMLString(htmlText!, baseURL: baseUrl) |
| | | } |
| | | } |
| | | |
| | |
| | | |
| | | import UIKit |
| | | import SVProgressHUD |
| | | import JQTools |
| | | |
| | | class SceneDelegate: UIResponder, UIWindowSceneDelegate { |
| | | |
| | | var window: UIWindow? |
| | | |
| | | |
| | | func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) { |
| | | guard let windowScene = (scene as? UIWindowScene) else { return } |
| | | window = UIWindow(windowScene: windowScene) |
| | | window?.frame = windowScene.coordinateSpace.bounds |
| | | |
| | | // if UserViewModel.getToken() != nil{ |
| | | // app.registerAndLoginSuccess() |
| | | // }else{ |
| | | // let loginNav = LoginNav(rootViewController: LoginVC()) |
| | | // window?.rootViewController = loginNav |
| | | // window?.makeKeyAndVisible() |
| | | // } |
| | | |
| | | let tabbar = BaseTabBarVC() |
| | | window?.rootViewController = tabbar |
| | | window?.makeKeyAndVisible() |
| | | tabbar.selectedIndex = 0 |
| | | |
| | | |
| | | SVProgressHUD.setContainerView(window) |
| | | SVProgressHUD.setDefaultStyle(.dark) |
| | |
| | | } |
| | | |
| | | func needLogin(){ |
| | | |
| | | let loginNav = LoginNav(rootViewController: LoginVC()) |
| | | loginNav.modalPresentationStyle = .fullScreen |
| | | JQ_currentViewController().present(loginNav, animated: true) |
| | | } |
| | | func loginSuccess(){ |
| | | |
| | | } |
| | | |
| | | func sceneDidDisconnect(_ scene: UIScene) { |