杨锴
2024-09-05 586eb879891e852e50302206470149766c35ee08
fix API Login
15个文件已修改
12个文件已添加
585 ■■■■ 已修改文件
XQMuse.xcodeproj/project.pbxproj 20 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
XQMuse/Assets.xcassets/Icons/btn_eye_close.imageset/Contents.json 22 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
XQMuse/Assets.xcassets/Icons/btn_eye_close.imageset/btn_eye_close@2x.png 补丁 | 查看 | 原始文档 | blame | 历史
XQMuse/Assets.xcassets/Icons/btn_eye_close.imageset/btn_eye_close@3x.png 补丁 | 查看 | 原始文档 | blame | 历史
XQMuse/Assets.xcassets/Icons/icon_code.imageset/Contents.json 22 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
XQMuse/Assets.xcassets/Icons/icon_code.imageset/icon_code@2x.png 补丁 | 查看 | 原始文档 | blame | 历史
XQMuse/Assets.xcassets/Icons/icon_code.imageset/icon_code@3x.png 补丁 | 查看 | 原始文档 | blame | 历史
XQMuse/Assets.xcassets/Icons/icon_fail.imageset/Contents.json 22 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
XQMuse/Assets.xcassets/Icons/icon_fail.imageset/icon_fail@2x.png 补丁 | 查看 | 原始文档 | blame | 历史
XQMuse/Assets.xcassets/Icons/icon_fail.imageset/icon_fail@3x.png 补丁 | 查看 | 原始文档 | blame | 历史
XQMuse/Config/Types.swift 39 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
XQMuse/Root/Login/LoginVC.swift 54 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
XQMuse/Root/Login/LoginVC.xib 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
XQMuse/Root/Login/VC/ForgotPasswordChangeVC.swift 34 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
XQMuse/Root/Login/VC/ForgotPasswordChangeVC.xib 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
XQMuse/Root/Login/VC/ForgotPasswordInputCodeVC.swift 31 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
XQMuse/Root/Login/VC/ForgotPasswordVC.swift 3 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
XQMuse/Root/Login/VC/LoginTreatyVC.swift 27 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
XQMuse/Root/Login/VC/RegisterVC.swift 41 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
XQMuse/Root/Login/VC/RegisterVC.xib 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
XQMuse/Root/Login/View/Popup_1_View.swift 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
XQMuse/Root/Network/Models.swift 39 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
XQMuse/Root/Network/NetworkRequest.swift 45 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
XQMuse/Root/Network/Services.swift 75 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
XQMuse/Root/Network/ViewModels/UserViewModel.swift 42 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
XQMuse/Root/Other/WebVC.swift 29 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
XQMuse/SceneDelegate.swift 18 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
XQMuse.xcodeproj/project.pbxproj
@@ -85,6 +85,9 @@
        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 */; };
@@ -334,6 +337,9 @@
        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>"; };
@@ -641,6 +647,14 @@
            path = VC;
            sourceTree = "<group>";
        };
        135B1D232C8947570089A9BE /* ViewModels */ = {
            isa = PBXGroup;
            children = (
                135B1D242C8947630089A9BE /* UserViewModel.swift */,
            );
            path = ViewModels;
            sourceTree = "<group>";
        };
        135C2A552C7F033300CC2A67 /* CLFullScreenController */ = {
            isa = PBXGroup;
            children = (
@@ -790,8 +804,10 @@
        1385DFFF2C6C4F1200AADB1F /* Network */ = {
            isa = PBXGroup;
            children = (
                135B1D232C8947570089A9BE /* ViewModels */,
                1385DFFB2C6C4F1200AADB1F /* NetworkRequest.swift */,
                1385DFFD2C6C4F1200AADB1F /* Services.swift */,
                135B1D212C8868170089A9BE /* Models.swift */,
            );
            path = Network;
            sourceTree = "<group>";
@@ -871,6 +887,7 @@
                13985DB42C69B7DF0046B6DC /* Def.swift */,
                13985DB72C69B80D0046B6DC /* Themes.swift */,
                13897D882C7DB9D7006209E0 /* EqualCellSpaceFlowLayout.swift */,
                135B1D1F2C8863D10089A9BE /* Types.swift */,
            );
            path = Config;
            sourceTree = "<group>";
@@ -1333,6 +1350,8 @@
                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 */,
@@ -1453,6 +1472,7 @@
                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 */,
XQMuse/Assets.xcassets/Icons/btn_eye_close.imageset/Contents.json
New file
@@ -0,0 +1,22 @@
{
  "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
  }
}
XQMuse/Assets.xcassets/Icons/btn_eye_close.imageset/btn_eye_close@2x.png
XQMuse/Assets.xcassets/Icons/btn_eye_close.imageset/btn_eye_close@3x.png
XQMuse/Assets.xcassets/Icons/icon_code.imageset/Contents.json
New file
@@ -0,0 +1,22 @@
{
  "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
  }
}
XQMuse/Assets.xcassets/Icons/icon_code.imageset/icon_code@2x.png
XQMuse/Assets.xcassets/Icons/icon_code.imageset/icon_code@3x.png
XQMuse/Assets.xcassets/Icons/icon_fail.imageset/Contents.json
New file
@@ -0,0 +1,22 @@
{
  "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
  }
}
XQMuse/Assets.xcassets/Icons/icon_fail.imageset/icon_fail@2x.png
XQMuse/Assets.xcassets/Icons/icon_fail.imageset/icon_fail@3x.png
XQMuse/Config/Types.swift
New file
@@ -0,0 +1,39 @@
//
//  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
}
XQMuse/Root/Login/LoginVC.swift
@@ -12,10 +12,6 @@
class LoginViewModel{
                enum LoginType{
                                case pwd,code
                }
                var loginType = BehaviorRelay<LoginType>(value:.pwd)
                var loginPhone = BehaviorRelay<String>(value:"")
                var loginContent = BehaviorRelay<String>(value:"")
@@ -57,6 +53,7 @@
                @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()
@@ -113,6 +110,7 @@
                }
                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)
@@ -129,40 +127,74 @@
                @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)
                }
XQMuse/Root/Login/LoginVC.xib
@@ -11,6 +11,7 @@
        <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"/>
@@ -104,6 +105,7 @@
                            </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>
@@ -198,6 +200,9 @@
                            <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"/>
@@ -290,6 +295,7 @@
    <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"/>
XQMuse/Root/Login/VC/ForgotPasswordChangeVC.swift
@@ -13,14 +13,29 @@
                @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
@@ -38,14 +53,23 @@
                                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)
                }
}
XQMuse/Root/Login/VC/ForgotPasswordChangeVC.xib
@@ -12,6 +12,7 @@
        <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>
@@ -55,6 +56,10 @@
                    <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"/>
@@ -107,6 +112,7 @@
        </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"/>
XQMuse/Root/Login/VC/ForgotPasswordInputCodeVC.swift
@@ -43,7 +43,7 @@
                                super.viewDidAppear(animated)
                                c1.becomeFirstResponder()
                                c1.jq_borderWidth = 1
                                starTimer()
                                sendCode()
                }
    override func viewDidLoad() {
@@ -92,6 +92,13 @@
                                }
                }
                private func sendCode(){
                                Services.sendCode(type: .forgetPwd).subscribe(onNext: { _ in
                                                self.starTimer()
                                }).disposed(by: disposeBag)
                }
                private func starTimer(){
                                times = 60
                                btn_retry.isEnabled = false
@@ -115,19 +122,29 @@
                }
                @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()
                }
                
XQMuse/Root/Login/VC/ForgotPasswordVC.swift
@@ -36,6 +36,7 @@
                }
                @IBAction func checkingAction(_ sender: UIButton) {
                                view.endEditing(true)
                                if tf_phone.text!.isEmpty{
                                                alertError(msg: "请输入手机号");return
                                }
@@ -43,10 +44,8 @@
                                if !tf_phone.text!.jq_isPhone{
                                                alertError(msg: "请输入正确手机号");return
                                }
                                view.endEditing(true)
                                let vc = ForgotPasswordInputCodeVC(phone: tf_phone.text!)
                                push(vc: vc)
                }
                
XQMuse/Root/Login/VC/LoginTreatyVC.swift
@@ -12,7 +12,8 @@
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)
                                // 追踪线
@@ -50,6 +51,8 @@
                                pageVC.scrollview.bounces = false
                                return pageVC
                }()
                private var clouse:((Bool)->Void)!
                override func viewWillAppear(_ animated: Bool) {
                                super.viewWillAppear(animated)
                                UIView.animate(withDuration: 0.5) {
@@ -65,10 +68,16 @@
    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()
                                }
@@ -82,12 +91,18 @@
                                }
                }
                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)
                }
}
@@ -109,6 +124,14 @@
                }
                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)
                }
}
XQMuse/Root/Login/VC/RegisterVC.swift
@@ -56,7 +56,8 @@
                @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()
@@ -88,31 +89,49 @@
                                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)
                }
XQMuse/Root/Login/VC/RegisterVC.xib
@@ -11,6 +11,7 @@
    <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"/>
@@ -208,6 +209,9 @@
                    <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"/>
XQMuse/Root/Login/View/Popup_1_View.swift
@@ -32,6 +32,12 @@
                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
XQMuse/Root/Network/Models.swift
New file
@@ -0,0 +1,39 @@
//
//  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
}
XQMuse/Root/Network/NetworkRequest.swift
@@ -33,12 +33,6 @@
struct SimpleModel: HandyJSON {
}
struct HtmlModel: HandyJSON {
                var  content = ""
                var  content1 = ""
                var id = 0
                var type =  0
}
extension String: HandyJSON{
@@ -136,25 +130,26 @@
                /// 参数加密
                @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
                }
XQMuse/Root/Network/Services.swift
@@ -12,7 +12,7 @@
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
@@ -21,14 +21,71 @@
}
// 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)
                }
}
XQMuse/Root/Network/ViewModels/UserViewModel.swift
New file
@@ -0,0 +1,42 @@
//
//  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()
                }
}
XQMuse/Root/Other/WebVC.swift
@@ -7,12 +7,14 @@
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 = """
@@ -27,6 +29,11 @@
                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) {
@@ -65,12 +72,22 @@
                                                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)
                                }
                }
XQMuse/SceneDelegate.swift
@@ -7,29 +7,22 @@
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)
@@ -43,7 +36,12 @@
                }
                func needLogin(){
                                let loginNav = LoginNav(rootViewController: LoginVC())
                                loginNav.modalPresentationStyle = .fullScreen
                                JQ_currentViewController().present(loginNav, animated: true)
                }
                func loginSuccess(){
                }
                func sceneDidDisconnect(_ scene: UIScene) {