| | |
| | | 1319B0292C0818540052F889 /* HomeListenStory_2_VC.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1319B0282C0818540052F889 /* HomeListenStory_2_VC.swift */; }; |
| | | 1319B02C2C081A320052F889 /* SimpleImageCCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1319B02A2C081A320052F889 /* SimpleImageCCell.swift */; }; |
| | | 1319B02D2C081A320052F889 /* SimpleImageCCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = 1319B02B2C081A320052F889 /* SimpleImageCCell.xib */; }; |
| | | 1319B0312C0859370052F889 /* Services.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1319B02F2C0859370052F889 /* Services.swift */; }; |
| | | 1319B0322C0859370052F889 /* NetworkRequest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1319B0302C0859370052F889 /* NetworkRequest.swift */; }; |
| | | 1319B0352C0859E20052F889 /* UserViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1319B0342C0859E20052F889 /* UserViewModel.swift */; }; |
| | | 131C030A2C0D564000EA4C25 /* MarketTagCCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = 131C03092C0D564000EA4C25 /* MarketTagCCell.xib */; }; |
| | | 131C030B2C0D564000EA4C25 /* MarketTagCCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 131C03082C0D564000EA4C25 /* MarketTagCCell.swift */; }; |
| | | 131C030D2C0D6A4800EA4C25 /* CommonBannerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 131C030C2C0D6A4800EA4C25 /* CommonBannerView.swift */; }; |
| | | 131C03112C0DA5D500EA4C25 /* CityAddressPickerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 131C03102C0DA5D500EA4C25 /* CityAddressPickerView.swift */; }; |
| | | 133386382C007E91002EE788 /* HomeListenFight_lesson_2_VC.swift in Sources */ = {isa = PBXBuildFile; fileRef = 133386372C007E91002EE788 /* HomeListenFight_lesson_2_VC.swift */; }; |
| | | 13397D962C05EA9D003440F9 /* ListenFight_Game_CCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 13397D942C05EA9D003440F9 /* ListenFight_Game_CCell.swift */; }; |
| | | 13397D972C05EA9D003440F9 /* ListenFight_Game_CCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = 13397D952C05EA9D003440F9 /* ListenFight_Game_CCell.xib */; }; |
| | |
| | | 13A830FA2C043A0600BB2F23 /* Lesson_3_AnswerView.xib in Resources */ = {isa = PBXBuildFile; fileRef = 13A830F92C043A0600BB2F23 /* Lesson_3_AnswerView.xib */; }; |
| | | 13AA25392C00759600F075B3 /* HomeStudyCompleteVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = 13AA25372C00759600F075B3 /* HomeStudyCompleteVC.swift */; }; |
| | | 13AA253A2C00759600F075B3 /* HomeStudyCompleteVC.xib in Resources */ = {isa = PBXBuildFile; fileRef = 13AA25382C00759600F075B3 /* HomeStudyCompleteVC.xib */; }; |
| | | 13CD3AC72C0874B3007E1065 /* CommonModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 13CD3AC62C0874B3007E1065 /* CommonModel.swift */; }; |
| | | 13CD3AC92C0886E5007E1065 /* RefreshModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 13CD3AC82C0886E5007E1065 /* RefreshModel.swift */; }; |
| | | 13CDF4492C0566E400E8D4FD /* HomeListenFight_lesson_4_VC.swift in Sources */ = {isa = PBXBuildFile; fileRef = 13CDF4482C0566E400E8D4FD /* HomeListenFight_lesson_4_VC.swift */; }; |
| | | 13CDF44C2C056A6900E8D4FD /* ListenFight_lesson_4_CCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = 13CDF44B2C056A6900E8D4FD /* ListenFight_lesson_4_CCell.xib */; }; |
| | | 13CDF44D2C056A6900E8D4FD /* ListenFight_lesson_4_CCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 13CDF44A2C056A6900E8D4FD /* ListenFight_lesson_4_CCell.swift */; }; |
| | |
| | | 1319B0282C0818540052F889 /* HomeListenStory_2_VC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HomeListenStory_2_VC.swift; sourceTree = "<group>"; }; |
| | | 1319B02A2C081A320052F889 /* SimpleImageCCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SimpleImageCCell.swift; sourceTree = "<group>"; }; |
| | | 1319B02B2C081A320052F889 /* SimpleImageCCell.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = SimpleImageCCell.xib; sourceTree = "<group>"; }; |
| | | 1319B02F2C0859370052F889 /* Services.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Services.swift; sourceTree = "<group>"; }; |
| | | 1319B0302C0859370052F889 /* NetworkRequest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NetworkRequest.swift; sourceTree = "<group>"; }; |
| | | 1319B0342C0859E20052F889 /* UserViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserViewModel.swift; sourceTree = "<group>"; }; |
| | | 131C03082C0D564000EA4C25 /* MarketTagCCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MarketTagCCell.swift; sourceTree = "<group>"; }; |
| | | 131C03092C0D564000EA4C25 /* MarketTagCCell.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = MarketTagCCell.xib; sourceTree = "<group>"; }; |
| | | 131C030C2C0D6A4800EA4C25 /* CommonBannerView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CommonBannerView.swift; sourceTree = "<group>"; }; |
| | | 131C03102C0DA5D500EA4C25 /* CityAddressPickerView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CityAddressPickerView.swift; sourceTree = "<group>"; }; |
| | | 133386372C007E91002EE788 /* HomeListenFight_lesson_2_VC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HomeListenFight_lesson_2_VC.swift; sourceTree = "<group>"; }; |
| | | 13397D942C05EA9D003440F9 /* ListenFight_Game_CCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ListenFight_Game_CCell.swift; sourceTree = "<group>"; }; |
| | | 13397D952C05EA9D003440F9 /* ListenFight_Game_CCell.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = ListenFight_Game_CCell.xib; sourceTree = "<group>"; }; |
| | |
| | | 13A830F92C043A0600BB2F23 /* Lesson_3_AnswerView.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = Lesson_3_AnswerView.xib; sourceTree = "<group>"; }; |
| | | 13AA25372C00759600F075B3 /* HomeStudyCompleteVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HomeStudyCompleteVC.swift; sourceTree = "<group>"; }; |
| | | 13AA25382C00759600F075B3 /* HomeStudyCompleteVC.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = HomeStudyCompleteVC.xib; sourceTree = "<group>"; }; |
| | | 13CD3AC62C0874B3007E1065 /* CommonModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CommonModel.swift; sourceTree = "<group>"; }; |
| | | 13CD3AC82C0886E5007E1065 /* RefreshModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RefreshModel.swift; sourceTree = "<group>"; }; |
| | | 13CDF4482C0566E400E8D4FD /* HomeListenFight_lesson_4_VC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HomeListenFight_lesson_4_VC.swift; sourceTree = "<group>"; }; |
| | | 13CDF44A2C056A6900E8D4FD /* ListenFight_lesson_4_CCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ListenFight_lesson_4_CCell.swift; sourceTree = "<group>"; }; |
| | | 13CDF44B2C056A6900E8D4FD /* ListenFight_lesson_4_CCell.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = ListenFight_lesson_4_CCell.xib; sourceTree = "<group>"; }; |
| | |
| | | 130278282BFD957100DDCE81 /* DolphinEnglishLearnStudent */ = { |
| | | isa = PBXGroup; |
| | | children = ( |
| | | 13CD3AC52C08749E007E1065 /* Models */, |
| | | 1319B0332C0859D70052F889 /* ViewModel */, |
| | | 1319B02E2C08592D0052F889 /* Services */, |
| | | 130278632BFD9E5D00DDCE81 /* Moudle */, |
| | | 130278582BFD985E00DDCE81 /* Other */, |
| | | 1302784E2BFD97EF00DDCE81 /* Login */, |
| | |
| | | 130278472BFD979200DDCE81 /* Base */ = { |
| | | isa = PBXGroup; |
| | | children = ( |
| | | 1319B0362C085B040052F889 /* View */, |
| | | 130278432BFD979200DDCE81 /* BaseNav.swift */, |
| | | 130278442BFD979200DDCE81 /* BaseTabBarVC.swift */, |
| | | 130278452BFD979200DDCE81 /* BaseVC.swift */, |
| | |
| | | 130278562BFD985E00DDCE81 /* UIView */ = { |
| | | isa = PBXGroup; |
| | | children = ( |
| | | 131C030C2C0D6A4800EA4C25 /* CommonBannerView.swift */, |
| | | 130278512BFD985E00DDCE81 /* BitrhdayPickerView.swift */, |
| | | 130278522BFD985E00DDCE81 /* CommonAlertView.swift */, |
| | | 130278532BFD985E00DDCE81 /* CommonAlertView.xib */, |
| | |
| | | 130278552BFD985E00DDCE81 /* CommonInputView.xib */, |
| | | 1362C75E2BFF4BA900BD7F73 /* StudyHandleView.swift */, |
| | | 1362C7602BFF4BB100BD7F73 /* StudyHandleView.xib */, |
| | | 131C03102C0DA5D500EA4C25 /* CityAddressPickerView.swift */, |
| | | ); |
| | | path = UIView; |
| | | sourceTree = "<group>"; |
| | |
| | | children = ( |
| | | 1302786A2BFD9ED600DDCE81 /* MarketCCell.swift */, |
| | | 1302786B2BFD9ED600DDCE81 /* MarketCCell.xib */, |
| | | 131C03082C0D564000EA4C25 /* MarketTagCCell.swift */, |
| | | 131C03092C0D564000EA4C25 /* MarketTagCCell.xib */, |
| | | ); |
| | | path = CCell; |
| | | sourceTree = "<group>"; |
| | |
| | | 130278902BFD9FBF00DDCE81 /* Home_1_TCell.xib */, |
| | | ); |
| | | path = TCell; |
| | | sourceTree = "<group>"; |
| | | }; |
| | | 1319B02E2C08592D0052F889 /* Services */ = { |
| | | isa = PBXGroup; |
| | | children = ( |
| | | 1319B0302C0859370052F889 /* NetworkRequest.swift */, |
| | | 1319B02F2C0859370052F889 /* Services.swift */, |
| | | ); |
| | | path = Services; |
| | | sourceTree = "<group>"; |
| | | }; |
| | | 1319B0332C0859D70052F889 /* ViewModel */ = { |
| | | isa = PBXGroup; |
| | | children = ( |
| | | 13CD3AC82C0886E5007E1065 /* RefreshModel.swift */, |
| | | 1319B0342C0859E20052F889 /* UserViewModel.swift */, |
| | | ); |
| | | path = ViewModel; |
| | | sourceTree = "<group>"; |
| | | }; |
| | | 1319B0362C085B040052F889 /* View */ = { |
| | | isa = PBXGroup; |
| | | children = ( |
| | | ); |
| | | path = View; |
| | | sourceTree = "<group>"; |
| | | }; |
| | | 13649E992C002FDF001B04E2 /* CCell */ = { |
| | |
| | | 13AA25382C00759600F075B3 /* HomeStudyCompleteVC.xib */, |
| | | ); |
| | | path = VC; |
| | | sourceTree = "<group>"; |
| | | }; |
| | | 13CD3AC52C08749E007E1065 /* Models */ = { |
| | | isa = PBXGroup; |
| | | children = ( |
| | | 13CD3AC62C0874B3007E1065 /* CommonModel.swift */, |
| | | ); |
| | | path = Models; |
| | | sourceTree = "<group>"; |
| | | }; |
| | | 13EEB88F2BFED3C6002996FC /* View */ = { |
| | |
| | | 13EEB8A92BFF354B002996FC /* HomeListen_item_TCell.xib in Resources */, |
| | | 13CDF4512C05757400E8D4FD /* Lesson_4_AnswerView.xib in Resources */, |
| | | 1319B02D2C081A320052F889 /* SimpleImageCCell.xib in Resources */, |
| | | 131C030A2C0D564000EA4C25 /* MarketTagCCell.xib in Resources */, |
| | | 130278982BFD9FBF00DDCE81 /* GoodsItemTCell.xib in Resources */, |
| | | 13CDF44C2C056A6900E8D4FD /* ListenFight_lesson_4_CCell.xib in Resources */, |
| | | 130278962BFD9FBF00DDCE81 /* Home_1_TCell.xib in Resources */, |
| | |
| | | 130278992BFD9FBF00DDCE81 /* Home_1_TCell.swift in Sources */, |
| | | 1302784B2BFD979200DDCE81 /* TapBtn.swift in Sources */, |
| | | 13CDF44F2C05756C00E8D4FD /* Lesson_4_AnswerView.swift in Sources */, |
| | | 1319B0312C0859370052F889 /* Services.swift in Sources */, |
| | | 13EEB8A82BFF354B002996FC /* HomeListen_item_TCell.swift in Sources */, |
| | | 13A830F12C04196400BB2F23 /* HomeListenFight_lesson_3_VC.swift in Sources */, |
| | | 13CDF44D2C056A6900E8D4FD /* ListenFight_lesson_4_CCell.swift in Sources */, |
| | | 131C030B2C0D564000EA4C25 /* MarketTagCCell.swift in Sources */, |
| | | 13CD3AC72C0874B3007E1065 /* CommonModel.swift in Sources */, |
| | | 131C030D2C0D6A4800EA4C25 /* CommonBannerView.swift in Sources */, |
| | | 1319B0322C0859370052F889 /* NetworkRequest.swift in Sources */, |
| | | 1362C75F2BFF4BA900BD7F73 /* StudyHandleView.swift in Sources */, |
| | | 130278672BFD9E8C00DDCE81 /* HomeVC.swift in Sources */, |
| | | 131C03112C0DA5D500EA4C25 /* CityAddressPickerView.swift in Sources */, |
| | | 130278482BFD979200DDCE81 /* BaseNav.swift in Sources */, |
| | | 1319B0352C0859E20052F889 /* UserViewModel.swift in Sources */, |
| | | 130278622BFD999200DDCE81 /* LoginVC.swift in Sources */, |
| | | 13EEB89C2BFF1C35002996FC /* HomeListenMenuVC.swift in Sources */, |
| | | 13CDF4492C0566E400E8D4FD /* HomeListenFight_lesson_4_VC.swift in Sources */, |
| | |
| | | 1302788D2BFD9F4200DDCE81 /* CoinRecordHistoryVC.swift in Sources */, |
| | | 13A049FF2C058B1400F1F52E /* HomeListenFight_lesson_5_VC.swift in Sources */, |
| | | 1302785A2BFD985E00DDCE81 /* CommonAlertView.swift in Sources */, |
| | | 13CD3AC92C0886E5007E1065 /* RefreshModel.swift in Sources */, |
| | | 1302782C2BFD957100DDCE81 /* SceneDelegate.swift in Sources */, |
| | | 1302787D2BFD9ED600DDCE81 /* MarketExchangeVC.swift in Sources */, |
| | | 1302789A2BFD9FBF00DDCE81 /* AddressManageTCell.swift in Sources */, |
| | |
| | | } |
| | | |
| | | |
| | | func LogSuccess(_ items:Any...,separator:String=" ",file:String=#file,function:String=#function,line:Int=#line){ |
| | | #if DEBUG |
| | | if #available(iOS 14.0, *) { |
| | | let logger = Logger(subsystem: "English", category: function) |
| | | logger.error("\(items)") |
| | | }else{ |
| | | let file = (file as NSString).lastPathComponent.split(separator: ".").first!; |
| | | print("✅✅✅ SUCCESS: \(file) \(function) [Line: \(line)]: \(items)",separator); |
| | | } |
| | | |
| | | #endif |
| | | } |
| | | |
| | | func LogError(_ items:Any...,separator:String=" ",file:String=#file,function:String=#function,line:Int=#line){ |
| | | #if DEBUG |
| | | if #available(iOS 14.0, *) { |
| | | let logger = Logger(subsystem: "English", category: function) |
| | | logger.error("\(items)") |
| | | }else{ |
| | | let file = (file as NSString).lastPathComponent.split(separator: ".").first!; |
| | | print("❌❌❌ ERROR: \(file) \(function) [Line: \(line)]: \(items)",separator); |
| | | } |
| | | #endif |
| | | } |
| | | |
| | | func LogInfo(_ items:Any...,separator:String=" ",file:String=#file,function:String=#function,line:Int=#line){ |
| | | #if DEBUG |
| | | if #available(iOS 14.0, *) { |
| | | let logger = Logger(subsystem: "WanPai", category: function) |
| | | let logger = Logger(subsystem: "English", category: function) |
| | | logger.error("\(items)") |
| | | }else{ |
| | | let file = (file as NSString).lastPathComponent.split(separator: ".").first!; |
| | |
| | | #endif |
| | | } |
| | | |
| | | func LogResponse(_ items:Any...,separator:String=" ",file:String=#file,function:String=#function,line:Int=#line){ |
| | | #if DEBUG |
| | | print("返回数据") |
| | | print(items); |
| | | #endif |
| | | } |
| | | |
| | | //提示框 |
| | | func alert(msg: String) { |
| | | SVProgressHUD.showInfo(withStatus: msg) |
| | |
| | | alert(msg: "请输入验证码");return false |
| | | } |
| | | |
| | | guard tf_phone.text!.count != 6 else { |
| | | guard tf_authCode.text!.count == 6 else { |
| | | alert(msg: "请输入6位验证码");return false |
| | | } |
| | | return true |
| | |
| | | |
| | | /// 隐私协议 |
| | | @IBAction func privacyAction(_ sender: UIButton) { |
| | | let vc = CommonWebVC(type: .privacyAgreement) |
| | | let vc = CommonWebVC(type: .PrivacyPolicy) |
| | | vc.title = "隐私协议" |
| | | self.navigationController?.pushViewController(vc, animated: true) |
| | | } |
| | | |
| | | /// 用户协议 |
| | | @IBAction func privacyUserAction(_ sender: UIButton) { |
| | | let vc = CommonWebVC(type: .userAgreement) |
| | | let vc = CommonWebVC(type: .UserProtocol) |
| | | vc.title = "用户协议" |
| | | self.navigationController?.pushViewController(vc, animated: true) |
| | | } |
| | |
| | | |
| | | @IBAction func getCodeAction(_ sender: UIButton) { |
| | | guard authInputPhone() else {return} |
| | | sender.openCountDown(60, defultTitle: "获取验证码", textColor:UIColor(hexStr: "#41A2EB"), unenableColor: .gray) |
| | | Services.sendPhoneCode(phone: tf_phone.text!).subscribe(onNext: {_ in |
| | | sender.openCountDown(60, defultTitle: "获取验证码", textColor:UIColor(hexStr: "#41A2EB"), unenableColor: .gray) |
| | | }).disposed(by: disposeBag) |
| | | } |
| | | |
| | | @IBAction func loginAction(_ sender: UIButton) { |
| | |
| | | alert(msg: "请阅读并同意《隐私协议》《用户协议》");return |
| | | } |
| | | |
| | | sceneDelegate?.loginSuccess() |
| | | Services.login(phone: tf_phone.text!, code: tf_authCode.text!).subscribe(onNext: {result in |
| | | if var token = result.data?.token{ |
| | | token.request_time = Int(Date().timeIntervalSince1970) |
| | | LoginTokenModel.saveToken(token) |
| | | sceneDelegate?.loginSuccess() |
| | | } |
| | | }).disposed(by: disposeBag) |
| | | } |
| | | } |
| | |
| | | </constraints> |
| | | <inset key="imageEdgeInsets" minX="0.0" minY="0.0" maxX="2.2250738585072014e-308" maxY="0.0"/> |
| | | <state key="normal" image="btn_choose_u"/> |
| | | <state key="selected" image="btn_choose"/> |
| | | <connections> |
| | | <action selector="chooseAction:" destination="-1" eventType="touchUpInside" id="taa-1D-MNJ"/> |
| | | </connections> |
| | |
| | | </objects> |
| | | <resources> |
| | | <image name="bg_login" width="296" height="129"/> |
| | | <image name="btn_choose" width="28" height="28"/> |
| | | <image name="btn_choose_u" width="28" height="28"/> |
| | | <image name="icon_input_code" width="15" height="18"/> |
| | | <image name="icon_input_phone" width="16" height="18"/> |
New file |
| | |
| | | // |
| | | // CommonModel.swift |
| | | // DolphinEnglishLearnStudent |
| | | // |
| | | // Created by 无故事王国 on 2024/5/30. |
| | | // |
| | | |
| | | import Foundation |
| | | import HandyJSON |
| | | import UserDefaultsStore |
| | | |
| | | struct LoginModel:HandyJSON{ |
| | | var token:LoginTokenModel? |
| | | } |
| | | |
| | | struct LoginTokenModel:HandyJSON,Identifiable,Codable{ |
| | | static let idKey = \LoginTokenModel.id |
| | | var id: Int = 0 |
| | | |
| | | var access_token = "" |
| | | var expires_in = 0 |
| | | var request_time = 0 //请求时间 |
| | | |
| | | private static let userInfo = UserDefaultsStore<LoginTokenModel>(uniqueIdentifier: "LoginTokenModel")! |
| | | |
| | | static func saveToken(_ model:LoginTokenModel){ |
| | | do{ |
| | | try LoginTokenModel.userInfo.save(model) |
| | | }catch{ |
| | | |
| | | } |
| | | } |
| | | |
| | | static func isOverdue()->Bool{ |
| | | if let token = LoginTokenModel.getToken(){ |
| | | //过期时间(秒) |
| | | let overdueTimeval = token.expires_in * 60 + token.request_time |
| | | |
| | | if overdueTimeval < Int(Date().timeIntervalSince1970){ |
| | | return true |
| | | } |
| | | return false |
| | | } |
| | | return true |
| | | } |
| | | |
| | | static func getToken()->LoginTokenModel?{ |
| | | return LoginTokenModel.userInfo.allObjects().first |
| | | } |
| | | |
| | | static func clearToken(){ |
| | | LoginTokenModel.userInfo.deleteAll() |
| | | } |
| | | } |
| | | |
| | | |
| | | struct RecommendModel:HandyJSON{ |
| | | var basicCount: Int = 0 |
| | | var coverImg: String = "" |
| | | var createBy: String = "" |
| | | var createTime: String = "" |
| | | var detail: String = "" |
| | | var detailImg: String = "" |
| | | var disabled: Bool = false |
| | | var id: Int = 0 |
| | | var insertTime: String = "" |
| | | var integral: Int = 0 |
| | | var inventory: Int = 0 |
| | | var isDelete: Int = 0 |
| | | var name: String = "" |
| | | var price: Int = 0 |
| | | var surplus: Int = 0 |
| | | var total: Int = 0 |
| | | var type: Int = 0 |
| | | var typeIds: String = "" |
| | | var updateBy: String = "" |
| | | var updateTime: String = "" |
| | | var userCount: Int = 0 |
| | | } |
| | | |
| | | struct MarketModel:HandyJSON{ |
| | | var basicCount: Int = 0 |
| | | var coverImg: String = "" |
| | | var createBy: String = "" |
| | | var createTime: String = "" |
| | | var detail: String = "" |
| | | var detailImg: String = "" |
| | | var disabled: Bool = false |
| | | var id: Int = 0 |
| | | var integral: Int = 0 |
| | | var inventory: Int = 0 |
| | | var isDelete: Int = 0 |
| | | var name: String = "" |
| | | var price: Int = 0 |
| | | var surplus: Int = 0 |
| | | var total: Int = 0 |
| | | var type: Int = 0 |
| | | var typeIds: String = "" |
| | | var updateBy: String = "" |
| | | var updateTime: String = "" |
| | | var userCount: Int = 0 |
| | | } |
| | | |
| | | struct MarketTypeModel:HandyJSON,Hashable{ |
| | | var id = 0 |
| | | var name = "" |
| | | } |
| | | |
| | | struct MarketDetailModel:HandyJSON{ |
| | | var exchangeNumber: Int = 0 |
| | | var good: MarketModel? |
| | | var goodTypes = [MarketTypeModel]() |
| | | var orderNumber: String = "" |
| | | var recipient: MarketRecipientModel? |
| | | } |
| | | |
| | | struct MarketRecipientModel:HandyJSON,Hashable{ |
| | | var id = 0 |
| | | var name = "" |
| | | } |
| | | |
| | | struct AddressModel:HandyJSON{ |
| | | var address: String = "" |
| | | var city: String = "" |
| | | var cityCode: String = "" |
| | | var createBy: String = "" |
| | | var createTime: String = "" |
| | | var disabled: Bool = false |
| | | var id: Int = 0 |
| | | var isDefault: Int = 0 |
| | | var province: String = "" |
| | | var provinceCode: String = "" |
| | | var recipient: String = "" |
| | | var recipientPhone: String = "" |
| | | var updateBy: String = "" |
| | | var updateTime: String = "" |
| | | var userId: Int = 0 |
| | | } |
| | | |
| | | struct AddressTreeModel:HandyJSON{ |
| | | var id = 0 |
| | | var name = "" |
| | | var code = "" |
| | | var parentId = 0 |
| | | var children:[AddressTreeModel]? |
| | | } |
| | | |
| | | struct IntegralModel:HandyJSON{ |
| | | var createBy: String = "" |
| | | var createTime: String = "" |
| | | var disabled: Bool = false |
| | | var gameId: Int = 0 |
| | | var id: Int = 0 |
| | | var integral: String = "" |
| | | var method: String = "" |
| | | var storyId: Int = 0 |
| | | var type: String = "" |
| | | var updateBy: String = "" |
| | | var updateTime: String = "" |
| | | var userId: Int = 0 |
| | | } |
| | | |
| | | struct ExchangeRecordModel:HandyJSON{ |
| | | var completeTime: String = "" |
| | | var consigneeAddress: String = "" |
| | | var consigneeName: String = "" |
| | | var consigneePhone: String = "" |
| | | var count: Int = 0 |
| | | var createBy: String = "" |
| | | var createTime: String = "" |
| | | var disabled: Bool = false |
| | | var express: String = "" |
| | | var expressNumber: String = "" |
| | | var expressTime: String = "" |
| | | var goodsId: Int = 0 |
| | | var id: Int = 0 |
| | | var insertTime: String = "" |
| | | var integral: Int = 0 |
| | | var orderNumber: String = "" |
| | | var state: Int = 0 |
| | | var updateBy: String = "" |
| | | var updateTime: String = "" |
| | | var userId: Int = 0 |
| | | } |
| | | |
| | | struct StudyGamesModel:HandyJSON{ |
| | | var gameRecordList = [StudyGamesRecordModel]() |
| | | var record:StudyDataRecordModel? |
| | | } |
| | | |
| | | |
| | | struct StudyGamesRecordModel:HandyJSON{ |
| | | var accuracy: Int = 0 |
| | | var createBy: String? |
| | | var createTime: String? |
| | | var disabled: Bool = false |
| | | var gameDifficulty: Int = 0 |
| | | var gameId: Int = 0 |
| | | var gameName: String? |
| | | var id: Int = 0 |
| | | var updateBy: String? |
| | | var updateTime: String? |
| | | var userId: Int = 0 |
| | | var useTime: Int = 0 |
| | | } |
| | | |
| | | struct StudyDataRecordModel:HandyJSON{ |
| | | var answer: Int = 0 |
| | | var createBy: String? |
| | | var createTime: String? |
| | | var day: Int = 0 |
| | | var disabled: Bool = false |
| | | var id: Int = 0 |
| | | var induction: Int = 0 |
| | | var listen: Int = 0 |
| | | var look: Int = 0 |
| | | var monthStudy: Int = 0 |
| | | var pair: Int = 0 |
| | | var surplus: Int = 0 |
| | | var todayStudy: Int = 0 |
| | | var totalStudy: Int = 0 |
| | | var updateBy: String? |
| | | var updateTime: String? |
| | | var userId: Int = 0 |
| | | var week: Int = 0 |
| | | var weekStudy: Int = 0 |
| | | } |
| | | |
| | | struct ListenWeekModel:HandyJSON{ |
| | | var id = 0 |
| | | var day = 0 |
| | | var quarter = 0 |
| | | var title = "" |
| | | var totalIntegral = 0 |
| | | var type = 0 |
| | | var week = 0 |
| | | } |
| | |
| | | class AwardListCCell: UICollectionViewCell { |
| | | |
| | | @IBOutlet weak var image_awar: UIImageView! |
| | | @IBOutlet weak var label_title: UILabel! |
| | | override func awakeFromNib() { |
| | | super.awakeFromNib() |
| | | // Initialization code |
| | | } |
| | | |
| | | func setModel(_ model:RecommendModel){ |
| | | image_awar.sd_setImage(with: URL(string: model.coverImg)) |
| | | image_awar.jq_cornerRadius = 8 |
| | | label_title.text = model.name |
| | | } |
| | | |
| | | override func layoutSubviews() { |
| | | super.layoutSubviews() |
| | |
| | | <placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner"/> |
| | | <placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/> |
| | | <collectionViewCell opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" reuseIdentifier="_AwardListCCell" id="gTV-IL-0wX" customClass="AwardListCCell" customModule="DolphinEnglishLearnStudent" customModuleProvider="target"> |
| | | <rect key="frame" x="0.0" y="0.0" width="276" height="526"/> |
| | | <rect key="frame" x="0.0" y="0.0" width="243" height="526"/> |
| | | <autoresizingMask key="autoresizingMask"/> |
| | | <view key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center"> |
| | | <rect key="frame" x="0.0" y="0.0" width="276" height="526"/> |
| | | <rect key="frame" x="0.0" y="0.0" width="243" height="526"/> |
| | | <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/> |
| | | <subviews> |
| | | <imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="YbH-L3-L1g"> |
| | | <rect key="frame" x="0.0" y="0.0" width="276" height="359"/> |
| | | <rect key="frame" x="0.0" y="0.0" width="243" height="316"/> |
| | | <color key="backgroundColor" red="0.61960784310000006" green="0.54117647059999996" blue="0.85882352939999995" alpha="1" colorSpace="custom" customColorSpace="sRGB"/> |
| | | <constraints> |
| | | <constraint firstAttribute="width" secondItem="YbH-L3-L1g" secondAttribute="height" multiplier="1:1.3" id="K9A-Ng-kLe"/> |
| | | </constraints> |
| | | <userDefinedRuntimeAttributes> |
| | | <userDefinedRuntimeAttribute type="boolean" keyPath="ld_maskToBoundsXIB" value="YES"/> |
| | | <userDefinedRuntimeAttribute type="number" keyPath="ld_cornerRadiusXIB"> |
| | | <real key="value" value="8"/> |
| | | </userDefinedRuntimeAttribute> |
| | | </userDefinedRuntimeAttributes> |
| | | </imageView> |
| | | <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Label" textAlignment="natural" lineBreakMode="tailTruncation" numberOfLines="2" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="wPP-pc-amm"> |
| | | <rect key="frame" x="0.0" y="368" width="276" height="19.5"/> |
| | | <rect key="frame" x="0.0" y="325" width="243" height="44"/> |
| | | <constraints> |
| | | <constraint firstAttribute="height" constant="44" id="7Eh-PB-yFf"/> |
| | | </constraints> |
| | | <fontDescription key="fontDescription" type="system" weight="medium" pointSize="16"/> |
| | | <color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="0.80000000000000004" colorSpace="custom" customColorSpace="sRGB"/> |
| | | <nil key="highlightedColor"/> |
| | |
| | | <constraint firstAttribute="trailing" secondItem="wPP-pc-amm" secondAttribute="trailing" id="UHp-wV-FRO"/> |
| | | <constraint firstItem="YbH-L3-L1g" firstAttribute="leading" secondItem="gTV-IL-0wX" secondAttribute="leading" id="WD8-o4-ZS3"/> |
| | | </constraints> |
| | | <size key="customSize" width="276" height="526"/> |
| | | <size key="customSize" width="243" height="526"/> |
| | | <connections> |
| | | <outlet property="image_awar" destination="YbH-L3-L1g" id="kuW-TO-4BH"/> |
| | | <outlet property="label_title" destination="wPP-pc-amm" id="vw9-1s-r0k"/> |
| | | </connections> |
| | | <point key="canvasLocation" x="130.2439024390244" y="140.84745762711864"/> |
| | | <point key="canvasLocation" x="116.70731707317073" y="140.84745762711864"/> |
| | | </collectionViewCell> |
| | | </objects> |
| | | </document> |
| | |
| | | |
| | | override func viewDidLoad() { |
| | | super.viewDidLoad() |
| | | |
| | | AwardListView.show { |
| | | |
| | | } |
| | | Services.goodRecommend().subscribe(onNext: { data in |
| | | AwardListView.show(items: data.data ?? []) {[weak self] model in |
| | | let vc = MarketContentVC(goodsId: model.id) |
| | | self?.push(vc: vc) |
| | | } |
| | | }).disposed(by: disposeBag) |
| | | } |
| | | |
| | | @IBAction func listenAction(_ sender: UIButton) { |
| | |
| | | |
| | | class HomeListenMenuVC: BaseVC { |
| | | |
| | | |
| | | @IBOutlet weak var tableView: UITableView! |
| | | @IBOutlet weak var collectionView: UICollectionView! |
| | | |
| | | private var repeatColors = ["#F8A169","#92CADB","#9E8ADB","#6DD1BA","#37C06E","#DEB975","#C54A59","#5DA0D3","#F0C433","#DC4827"] |
| | | private var titleItems = ["第一季","第二季","第三季","第四季"] |
| | | private var selectIndexPath:IndexPath = IndexPath(row: 0, section: 0) |
| | | |
| | | private var dataItems = Array<[ListenWeekModel]>(repeating: [], count: 4) |
| | | |
| | | override func viewDidLoad() { |
| | | super.viewDidLoad() |
| | | getData() |
| | | } |
| | | |
| | | |
| | | private func getData(){ |
| | | Services.weekList(quarter: selectIndexPath.row).subscribe(onNext: {result in |
| | | self.dataItems[self.selectIndexPath.row] = result.data ?? [] |
| | | self.collectionView.reloadData() |
| | | }).disposed(by: disposeBag) |
| | | } |
| | | |
| | | override func setUI() { |
| | |
| | | } |
| | | |
| | | func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { |
| | | return 20 |
| | | return dataItems[selectIndexPath.row].count |
| | | } |
| | | |
| | | func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize { |
| | |
| | | extension HomeListenMenuVC:UITableViewDataSource,UITableViewDelegate{ |
| | | func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { |
| | | selectIndexPath = indexPath |
| | | |
| | | if dataItems[indexPath.row].count == 0{ |
| | | getData() |
| | | } |
| | | tableView.reloadData() |
| | | } |
| | | |
| | |
| | | |
| | | @IBOutlet weak var collectionView: UICollectionView! |
| | | @IBOutlet weak var view_container: UIView! |
| | | private var items = [RecommendModel]() |
| | | private var clickClouse:((RecommendModel)->Void)! |
| | | override func awakeFromNib() { |
| | | super.awakeFromNib() |
| | | self.alpha = 0 |
| | |
| | | layoutIfNeeded() |
| | | } |
| | | |
| | | static func show(clouse:@escaping ()->Void){ |
| | | static func show(items:[RecommendModel],clouse:@escaping (RecommendModel)->Void){ |
| | | |
| | | if items.count == 0{return} |
| | | |
| | | let awardListView = AwardListView.jq_loadNibView() |
| | | awardListView.items = items |
| | | awardListView.clickClouse = clouse |
| | | sceneDelegate?.window?.addSubview(awardListView) |
| | | awardListView.frame = sceneDelegate?.window?.frame ?? .zero |
| | | |
| | |
| | | awardListView.alpha = 1 |
| | | awardListView.view_container.transform = .init(translationX: 1.0, y: 1.0) |
| | | awardListView.layoutIfNeeded() |
| | | }completion: { _ in |
| | | awardListView.collectionView.reloadData() |
| | | } |
| | | } |
| | | |
| | |
| | | } |
| | | |
| | | extension AwardListView:UICollectionViewDelegate{ |
| | | func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) { |
| | | |
| | | |
| | | UIView.animate(withDuration: 0.4) { |
| | | self.alpha = 0 |
| | | self.view_container.transform = .init(scaleX: 0.1, y: 0.1) |
| | | } completion: { _ in |
| | | self.removeFromSuperview() |
| | | let item = self.items[indexPath.row] |
| | | self.clickClouse(item) |
| | | } |
| | | } |
| | | } |
| | | |
| | | extension AwardListView:UICollectionViewDataSource{ |
| | | func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { |
| | | let item = items[indexPath.row] |
| | | let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "_AwardListCCell", for: indexPath) as! AwardListCCell |
| | | cell.setModel(item) |
| | | return cell |
| | | } |
| | | |
| | | func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { |
| | | return 6 |
| | | return items.count |
| | | } |
| | | } |
| | | |
| | | extension AwardListView:UICollectionViewDelegateFlowLayout{ |
| | | func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize { |
| | | let w = (self.jq_width - 74 - 190) / 3.0 |
| | | let w = (JQ_ScreenW - 37 * 2 - 144 * 2 - 44 * 2) / 3.0 |
| | | return CGSize(width: w, height: w * 1.552) |
| | | } |
| | | |
| | |
| | | |
| | | } |
| | | |
| | | var marketModel:MarketModel?{ |
| | | didSet{ |
| | | if let m = marketModel{ |
| | | cover_imageView.sd_setImage(with: URL(string: m.coverImg)) |
| | | label_title.text = m.name |
| | | label_coin.text = "\(m.integral)积分" |
| | | } |
| | | } |
| | | } |
| | | |
| | | override func layoutSubviews() { |
| | | super.layoutSubviews() |
| | | jq_addShadows(shadowColor: UIColor(hexStr: "#D9D9D9"), corner: 8, radius: 20, offset: CGSize(width: 0, height: 20), opacity: 1) |
New file |
| | |
| | | // |
| | | // MarketTagCCell.swift |
| | | // DolphinEnglishLearnStudent |
| | | // |
| | | // Created by 无故事王国 on 2024/6/3. |
| | | // |
| | | |
| | | import UIKit |
| | | |
| | | class MarketTagCCell: UICollectionViewCell { |
| | | |
| | | @IBOutlet weak var view_container: UIView! |
| | | @IBOutlet weak var label_name: UILabel! |
| | | |
| | | override func awakeFromNib() { |
| | | super.awakeFromNib() |
| | | view_container.jq_borderColor = UIColor(hexString: "#41A2EB") |
| | | } |
| | | |
| | | } |
New file |
| | |
| | | <?xml version="1.0" encoding="UTF-8"?> |
| | | <document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="32700.99.1234" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES"> |
| | | <device id="ipad10_9rounded" orientation="portrait" layout="fullscreen" appearance="light"/> |
| | | <dependencies> |
| | | <deployment identifier="iOS"/> |
| | | <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="22684"/> |
| | | <capability name="System colors in document resources" minToolsVersion="11.0"/> |
| | | <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/> |
| | | </dependencies> |
| | | <objects> |
| | | <placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner"/> |
| | | <placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/> |
| | | <collectionViewCell opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" reuseIdentifier="_MarketTagCCell" id="gTV-IL-0wX" customClass="MarketTagCCell" customModule="DolphinEnglishLearnStudent" customModuleProvider="target"> |
| | | <rect key="frame" x="0.0" y="0.0" width="106" height="66"/> |
| | | <autoresizingMask key="autoresizingMask"/> |
| | | <view key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center"> |
| | | <rect key="frame" x="0.0" y="0.0" width="106" height="66"/> |
| | | <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/> |
| | | <subviews> |
| | | <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="ynz-c6-wvK"> |
| | | <rect key="frame" x="0.0" y="0.0" width="106" height="66"/> |
| | | <subviews> |
| | | <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Label" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="fam-fP-fIA"> |
| | | <rect key="frame" x="17" y="10" width="72" height="47"/> |
| | | <fontDescription key="fontDescription" type="system" weight="semibold" pointSize="16"/> |
| | | <color key="textColor" red="0.25490196079999999" green="0.63529411759999999" blue="0.92156862750000001" alpha="1" colorSpace="custom" customColorSpace="sRGB"/> |
| | | <nil key="highlightedColor"/> |
| | | </label> |
| | | </subviews> |
| | | <color key="backgroundColor" systemColor="systemBackgroundColor"/> |
| | | <constraints> |
| | | <constraint firstAttribute="trailing" secondItem="fam-fP-fIA" secondAttribute="trailing" constant="17" id="Zzp-0t-bAM"/> |
| | | <constraint firstAttribute="bottom" secondItem="fam-fP-fIA" secondAttribute="bottom" constant="9" id="aCk-9L-SKS"/> |
| | | <constraint firstItem="fam-fP-fIA" firstAttribute="top" secondItem="ynz-c6-wvK" secondAttribute="top" constant="10" id="k72-Fv-BOv"/> |
| | | <constraint firstItem="fam-fP-fIA" firstAttribute="leading" secondItem="ynz-c6-wvK" secondAttribute="leading" constant="17" id="wC7-gL-7u1"/> |
| | | </constraints> |
| | | <userDefinedRuntimeAttributes> |
| | | <userDefinedRuntimeAttribute type="boolean" keyPath="ld_maskToBoundsXIB" value="YES"/> |
| | | <userDefinedRuntimeAttribute type="number" keyPath="ld_cornerRadiusXIB"> |
| | | <real key="value" value="20.5"/> |
| | | </userDefinedRuntimeAttribute> |
| | | </userDefinedRuntimeAttributes> |
| | | </view> |
| | | </subviews> |
| | | </view> |
| | | <constraints> |
| | | <constraint firstAttribute="trailing" secondItem="ynz-c6-wvK" secondAttribute="trailing" id="QjW-oE-Tgj"/> |
| | | <constraint firstAttribute="bottom" secondItem="ynz-c6-wvK" secondAttribute="bottom" id="e07-4t-A2U"/> |
| | | <constraint firstItem="ynz-c6-wvK" firstAttribute="top" secondItem="gTV-IL-0wX" secondAttribute="top" id="ew2-Uv-ect"/> |
| | | <constraint firstItem="ynz-c6-wvK" firstAttribute="leading" secondItem="gTV-IL-0wX" secondAttribute="leading" id="ohm-Eq-BKS"/> |
| | | </constraints> |
| | | <size key="customSize" width="106" height="66"/> |
| | | <connections> |
| | | <outlet property="label_name" destination="fam-fP-fIA" id="uca-7s-UDX"/> |
| | | <outlet property="view_container" destination="ynz-c6-wvK" id="05W-u9-fnI"/> |
| | | </connections> |
| | | <point key="canvasLocation" x="68.048780487804876" y="23.898305084745765"/> |
| | | </collectionViewCell> |
| | | </objects> |
| | | <resources> |
| | | <systemColor name="systemBackgroundColor"> |
| | | <color white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/> |
| | | </systemColor> |
| | | </resources> |
| | | </document> |
| | |
| | | |
| | | import UIKit |
| | | import QMUIKit |
| | | import RxRelay |
| | | import RxSwift |
| | | |
| | | class MarketListViewModel:RefreshInnerModel<MarketModel>{ |
| | | |
| | | let keywords = BehaviorRelay<String>(value:"") |
| | | let types = BehaviorRelay<[String]>(value:[]) |
| | | let menuTypes = BehaviorRelay<[MarketTypeModel]>(value:[]) |
| | | var selectMenuTypes = Set<MarketTypeModel>(){ |
| | | didSet{ |
| | | types.accept(selectMenuTypes.map({$0.name})) |
| | | beginRefresh() |
| | | } |
| | | } |
| | | |
| | | override func api() -> (Observable<BaseResponse<BaseResponseList<MarketModel>>>)? { |
| | | Services.goodsList(keywords: keywords.value, page: page, type: types.value) |
| | | } |
| | | } |
| | | |
| | | |
| | | class MarketVC: BaseVC { |
| | | @IBOutlet weak var tf_search: QMUITextField! |
| | | @IBOutlet weak var menu_collectView: UICollectionView! |
| | | @IBOutlet weak var content_collectionView: UICollectionView! |
| | | @IBOutlet weak var label_surplusCoin: UILabel! |
| | | |
| | | private let viewModel = MarketListViewModel() |
| | | |
| | | private var cellW = (JQ_ScreenW - 130 - 15) / 4.0 |
| | | |
| | | override func viewDidLoad() { |
| | | super.viewDidLoad() |
| | | |
| | | viewModel.configure(content_collectionView,needMore: true) |
| | | viewModel.beginRefresh() |
| | | |
| | | Services.getIntegral().subscribe(onNext: {[weak self] result in |
| | | self?.label_surplusCoin.text = "\(result.data ?? 0)" |
| | | }).disposed(by: disposeBag) |
| | | |
| | | Services.goodTypeStudy().subscribe(onNext: {[weak self] result in |
| | | self?.viewModel.menuTypes.accept(result.data ?? []) |
| | | self?.menu_collectView.reloadData() |
| | | }).disposed(by: disposeBag) |
| | | } |
| | | |
| | | override func setUI() { |
| | |
| | | content_collectionView.backgroundColor = .clear |
| | | content_collectionView.contentInset = UIEdgeInsets(top: 0, left: 65, bottom: 0, right:65) |
| | | content_collectionView.register(UINib(nibName: "MarketCCell", bundle: nil), forCellWithReuseIdentifier: "_MarketCCell") |
| | | tf_search.returnKeyType = .search |
| | | tf_search.delegate = self |
| | | |
| | | menu_collectView.backgroundColor = .clear |
| | | menu_collectView.dataSource = self |
| | | menu_collectView.delegate = self |
| | | menu_collectView.register(UINib(nibName: "MarketTagCCell", bundle: nil), forCellWithReuseIdentifier: "_MarketTagCCell") |
| | | } |
| | | |
| | | @IBAction func searchAction(_ sender: UIButton) { |
| | | |
| | | view.endEditing(true) |
| | | viewModel.keywords.accept(tf_search.text!) |
| | | viewModel.beginRefresh() |
| | | } |
| | | } |
| | | |
| | | extension MarketVC:UICollectionViewDelegate{ |
| | | func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) { |
| | | let vc = MarketContentVC() |
| | | vc.title = "商品详情" |
| | | push(vc: vc) |
| | | |
| | | if collectionView == menu_collectView{ |
| | | let model = viewModel.menuTypes.value[indexPath.row] |
| | | if viewModel.selectMenuTypes.contains(model){ |
| | | viewModel.selectMenuTypes.remove(model) |
| | | }else{ |
| | | viewModel.selectMenuTypes.insert(model) |
| | | } |
| | | collectionView.reloadData() |
| | | }else{ |
| | | let v = viewModel.dataSource.value?.records[indexPath.row] |
| | | let vc = MarketContentVC(goodsId: v?.id ?? 0) |
| | | vc.title = "商品详情" |
| | | push(vc: vc) |
| | | } |
| | | } |
| | | } |
| | | |
| | | extension MarketVC:UICollectionViewDataSource{ |
| | | func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { |
| | | return 30 |
| | | |
| | | if collectionView == menu_collectView{ |
| | | return viewModel.menuTypes.value.count |
| | | } |
| | | |
| | | return viewModel.dataSource.value?.records.count ?? 0 |
| | | } |
| | | |
| | | func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { |
| | | |
| | | if collectionView == menu_collectView{ |
| | | let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "_MarketTagCCell", for: indexPath) as! MarketTagCCell |
| | | let model = viewModel.menuTypes.value[indexPath.row] |
| | | cell.label_name.text = model.name |
| | | |
| | | if viewModel.selectMenuTypes.contains(model){ |
| | | cell.view_container.backgroundColor = UIColor(hexString: "#41A2EB") |
| | | cell.view_container.jq_borderWidth = 0 |
| | | cell.label_name.textColor = .white |
| | | }else{ |
| | | cell.view_container.backgroundColor = UIColor.white |
| | | cell.view_container.jq_borderWidth = 1 |
| | | cell.label_name.textColor = UIColor(hexString: "#41A2EB") |
| | | } |
| | | return cell |
| | | } |
| | | |
| | | let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "_MarketCCell", for: indexPath) as! MarketCCell |
| | | cell.backgroundColor = .gray.withAlphaComponent(0.5) |
| | | let model = viewModel.dataSource.value?.records[indexPath.row] |
| | | cell.marketModel = model |
| | | cell.backgroundColor = .white |
| | | return cell |
| | | } |
| | | } |
| | | |
| | | extension MarketVC:UICollectionViewDelegateFlowLayout{ |
| | | func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize { |
| | | |
| | | if collectionView == menu_collectView{ |
| | | return CGSize(width: 100, height: 41) |
| | | } |
| | | |
| | | return CGSize(width: cellW, height: cellW * 1.09) |
| | | } |
| | | |
| | | func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumLineSpacingForSectionAt section: Int) -> CGFloat { |
| | | if collectionView == menu_collectView{ |
| | | return 29 |
| | | } |
| | | return 24 |
| | | } |
| | | |
| | |
| | | return 5 |
| | | } |
| | | } |
| | | |
| | | extension MarketVC:QMUITextFieldDelegate{ |
| | | func textFieldShouldReturn(_ textField: UITextField) -> Bool { |
| | | view.endEditing(true) |
| | | viewModel.keywords.accept(textField.text!) |
| | | viewModel.beginRefresh() |
| | | return true |
| | | } |
| | | } |
| | |
| | | <placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner" customClass="MarketVC" customModule="DolphinEnglishLearnStudent" customModuleProvider="target"> |
| | | <connections> |
| | | <outlet property="content_collectionView" destination="EPp-Vf-S4a" id="nYe-TY-YF6"/> |
| | | <outlet property="label_surplusCoin" destination="82B-Dg-Sap" id="oRO-iM-jgF"/> |
| | | <outlet property="menu_collectView" destination="OCn-Jg-gWg" id="v5E-bg-k90"/> |
| | | <outlet property="tf_search" destination="Jv9-DX-cX8" id="Y6V-ux-8OL"/> |
| | | <outlet property="view" destination="i5M-Pr-FkT" id="sfx-zR-JGt"/> |
| | |
| | | |
| | | import UIKit |
| | | import WebKit |
| | | import RxRelay |
| | | |
| | | class MarketContentViewModel{ |
| | | //购买数量 |
| | | var number = BehaviorRelay<Int>(value:1) |
| | | var detailModel = BehaviorRelay<MarketDetailModel?>(value:nil) |
| | | var surplusCoin = BehaviorRelay<Int>(value:0) |
| | | var goodsId = BehaviorRelay<Int>(value:0) |
| | | |
| | | // var orderNumber = BehaviorRelay<String>(value:"") |
| | | //收获地址 |
| | | var address = BehaviorRelay<[AddressModel]>(value: []) |
| | | } |
| | | |
| | | class MarketContentVC: BaseVC { |
| | | |
| | | @IBOutlet weak var scrollView: UIScrollView! |
| | | @IBOutlet weak var image_cover: UIImageView! |
| | | @IBOutlet weak var view_banner: CommonBannerView! |
| | | @IBOutlet weak var view_footer: UIView! |
| | | @IBOutlet weak var view_container: UIView! |
| | | @IBOutlet weak var label_coin: UILabel! |
| | |
| | | @IBOutlet weak var label_surplusCoin: UILabel! |
| | | @IBOutlet weak var label_costCoin: UILabel! |
| | | @IBOutlet weak var cons_footHei: NSLayoutConstraint! |
| | | @IBOutlet weak var webViewHeiCons: NSLayoutConstraint! |
| | | |
| | | private var viewModel = MarketContentViewModel() |
| | | |
| | | required init(goodsId:Int) { |
| | | super.init(nibName: nil, bundle: nil) |
| | | self.viewModel.goodsId.accept(goodsId) |
| | | } |
| | | |
| | | required init?(coder: NSCoder) { |
| | | fatalError("init(coder:) has not been implemented") |
| | | } |
| | | |
| | | override func viewDidLoad() { |
| | | super.viewDidLoad() |
| | | |
| | | Services.goodsDetail(goodsId: viewModel.goodsId.value).subscribe(onNext: {[weak self] result in |
| | | if let m = result.data{ |
| | | |
| | | let banner = m.good?.detailImg.components(separatedBy: ",").map({ url in |
| | | return CommonBannerModel(index: 0, id: 0, name: nil, resource: url, mediaType: .imageUrl) |
| | | }) |
| | | |
| | | self?.view_banner.setItems(items: banner ?? [], autoRoll: true, selectClouse: nil) |
| | | |
| | | self?.label_coin.text = "\(m.good?.integral ?? 0)" |
| | | self?.label_costCoin.text = "\(m.good?.integral ?? 0)" |
| | | self?.label_title.text = m.good?.name ?? "" |
| | | self?.label_categry.text = m.goodTypes.map({$0.name}).joined(separator: "|") |
| | | |
| | | var info_Array = Array<String>() |
| | | info_Array.append("剩余数量:\(m.good?.surplus ?? 0)") |
| | | info_Array.append("可换数量:\(m.good?.userCount ?? 0)") |
| | | info_Array.append("\(m.exchangeNumber)人兑换") |
| | | |
| | | self?.label_info.text = info_Array.joined(separator: "|") |
| | | self?.webView.loadHTMLString(m.good?.detail.jq_wrapHtml() ?? "", baseURL: nil) |
| | | self?.viewModel.detailModel.accept(m) |
| | | } |
| | | |
| | | }).disposed(by: disposeBag) |
| | | |
| | | Services.getIntegral().subscribe(onNext: {[weak self] result in |
| | | self?.label_surplusCoin.text = "剩余积分:\(result.data ?? 0)" |
| | | self?.viewModel.surplusCoin.accept(result.data ?? 0) |
| | | }).disposed(by: disposeBag) |
| | | } |
| | | |
| | | override func setUI() { |
| | |
| | | cons_footHei.constant = 54 + UIDevice.jq_safeEdges.bottom |
| | | } |
| | | |
| | | override func setRx() { |
| | | webView.scrollView.rx.observe(CGSize.self, "contentSize").map { (size) -> CGFloat? in |
| | | if let size = size{ |
| | | return size.height |
| | | } |
| | | return nil |
| | | }.subscribe(onNext: { [unowned self](height) in |
| | | if let height = height{ |
| | | self.webViewHeiCons.constant = height |
| | | } |
| | | }).disposed(by: disposeBag) |
| | | } |
| | | |
| | | |
| | | @IBAction func exchangeAction(_ sender: UIButton) { |
| | | // CommonAlertView.show(isSinple: true, content: "兑换失败,当前剩余积分不足!") { |
| | | // |
| | | // } |
| | | |
| | | let vc = MarketExchangeVC() |
| | | guard viewModel.detailModel.value?.good?.surplus != 0 else { |
| | | CommonAlertView.show(isSinple: true, content: "兑换失败,当前剩余数量不足!") { |
| | | |
| | | } |
| | | return |
| | | } |
| | | |
| | | guard viewModel.detailModel.value?.good?.userCount != 0 else { |
| | | CommonAlertView.show(isSinple: true, content: "兑换失败,当前可换数量不足!") { |
| | | |
| | | } |
| | | return |
| | | } |
| | | |
| | | guard (viewModel.detailModel.value?.good?.integral ?? 0) < viewModel.surplusCoin.value else { |
| | | CommonAlertView.show(isSinple: true, content: "兑换失败,当前剩余积分不足!") { |
| | | |
| | | } |
| | | return |
| | | } |
| | | |
| | | let vc = MarketExchangeVC(viewModel: viewModel) |
| | | vc.title = "立即兑换" |
| | | push(vc: vc) |
| | | } |
| | | |
| | | override func viewDidLayoutSubviews() { |
| | | super.viewDidLayoutSubviews() |
| | | image_cover.jq_addCorners(corner: [.topLeft,.topRight], radius: 8) |
| | | view_banner.jq_addCorners(corner: [.topLeft,.topRight], radius: 8) |
| | | view_footer.jq_addShadows(shadowColor: UIColor(hexStr: "#DEDEDE").withAlphaComponent(0.5), corner: 0, radius: 4, offset: CGSize(width: 0, height: -1), opacity: 1) |
| | | |
| | | view_container.jq_addShadows(shadowColor: UIColor(hexStr: "#D9D9D9").withAlphaComponent(0.28), corner: 8, radius: 5, offset: CGSize(width: 0, height: 2), opacity: 1) |
| | |
| | | <placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner" customClass="MarketContentVC" customModule="DolphinEnglishLearnStudent" customModuleProvider="target"> |
| | | <connections> |
| | | <outlet property="cons_footHei" destination="O1c-0y-Iw9" id="Oj2-S6-uVD"/> |
| | | <outlet property="image_cover" destination="HQ8-qZ-zeA" id="0xr-UI-5I9"/> |
| | | <outlet property="label_categry" destination="YLo-dD-PTM" id="kCG-k8-Baa"/> |
| | | <outlet property="label_coin" destination="yrU-ab-vv9" id="4UT-Q9-CO3"/> |
| | | <outlet property="label_costCoin" destination="Br9-rb-zWu" id="Qyp-x1-Ff0"/> |
| | |
| | | <outlet property="label_title" destination="PgE-zX-EIu" id="FWi-qa-sK0"/> |
| | | <outlet property="scrollView" destination="loc-rm-BZe" id="xqU-OW-GgJ"/> |
| | | <outlet property="view" destination="i5M-Pr-FkT" id="sfx-zR-JGt"/> |
| | | <outlet property="view_banner" destination="lUx-IV-YIU" id="9RA-3Q-ceF"/> |
| | | <outlet property="view_container" destination="3V0-GL-Fmn" id="D6J-fr-4H2"/> |
| | | <outlet property="view_footer" destination="mp9-Bg-Kez" id="41u-8O-co7"/> |
| | | <outlet property="webView" destination="ZOY-ws-sjP" id="bXL-3r-nKs"/> |
| | | <outlet property="webViewHeiCons" destination="xMb-sR-Ext" id="8RD-Be-b0n"/> |
| | | </connections> |
| | | </placeholder> |
| | | <placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/> |
| | |
| | | <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="3V0-GL-Fmn"> |
| | | <rect key="frame" x="0.0" y="0.0" width="556" height="681"/> |
| | | <subviews> |
| | | <imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="HQ8-qZ-zeA"> |
| | | <rect key="frame" x="0.0" y="0.0" width="556" height="319.5"/> |
| | | <color key="backgroundColor" systemColor="systemGray5Color"/> |
| | | <constraints> |
| | | <constraint firstAttribute="width" secondItem="HQ8-qZ-zeA" secondAttribute="height" multiplier="1:0.575" id="4sO-41-6AB"/> |
| | | </constraints> |
| | | </imageView> |
| | | <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="0" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="yrU-ab-vv9"> |
| | | <rect key="frame" x="14" y="329.5" width="10" height="25"/> |
| | | <constraints> |
| | |
| | | <wkPreferences key="preferences"/> |
| | | </wkWebViewConfiguration> |
| | | </wkWebView> |
| | | <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="lUx-IV-YIU" customClass="CommonBannerView" customModule="DolphinEnglishLearnStudent" customModuleProvider="target"> |
| | | <rect key="frame" x="0.0" y="0.0" width="556" height="319.5"/> |
| | | <color key="backgroundColor" systemColor="systemBackgroundColor"/> |
| | | <constraints> |
| | | <constraint firstAttribute="width" secondItem="lUx-IV-YIU" secondAttribute="height" multiplier="1:0.575" id="Vfi-RM-kqs"/> |
| | | </constraints> |
| | | </view> |
| | | </subviews> |
| | | <color key="backgroundColor" systemColor="systemBackgroundColor"/> |
| | | <constraints> |
| | | <constraint firstItem="yrU-ab-vv9" firstAttribute="top" secondItem="lUx-IV-YIU" secondAttribute="bottom" constant="10" id="0Z9-Wg-moE"/> |
| | | <constraint firstItem="fkp-fX-eUo" firstAttribute="top" secondItem="3WZ-Jf-leh" secondAttribute="bottom" constant="15" id="1lu-mH-O3t"/> |
| | | <constraint firstItem="HQ8-qZ-zeA" firstAttribute="leading" secondItem="3V0-GL-Fmn" secondAttribute="leading" id="2L8-TY-eC1"/> |
| | | <constraint firstAttribute="trailing" secondItem="SHM-HW-3QJ" secondAttribute="trailing" constant="14" id="3fT-Df-Icu"/> |
| | | <constraint firstItem="ZOY-ws-sjP" firstAttribute="top" secondItem="fkp-fX-eUo" secondAttribute="bottom" constant="10" id="4Sb-GV-SMH"/> |
| | | <constraint firstItem="fkp-fX-eUo" firstAttribute="leading" secondItem="3V0-GL-Fmn" secondAttribute="leading" constant="14" id="CGr-W8-bYc"/> |
| | | <constraint firstItem="lUx-IV-YIU" firstAttribute="top" secondItem="3V0-GL-Fmn" secondAttribute="top" id="CJV-El-ct7"/> |
| | | <constraint firstItem="LtS-Mg-aeT" firstAttribute="centerY" secondItem="yrU-ab-vv9" secondAttribute="centerY" id="Eqy-fC-VXN"/> |
| | | <constraint firstItem="SHM-HW-3QJ" firstAttribute="leading" secondItem="3V0-GL-Fmn" secondAttribute="leading" constant="14" id="IcX-sV-UsY"/> |
| | | <constraint firstAttribute="trailing" secondItem="PgE-zX-EIu" secondAttribute="trailing" constant="14" id="KOH-43-2e0"/> |
| | | <constraint firstItem="lUx-IV-YIU" firstAttribute="leading" secondItem="3V0-GL-Fmn" secondAttribute="leading" id="OoB-ef-zF5"/> |
| | | <constraint firstItem="3WZ-Jf-leh" firstAttribute="top" secondItem="SHM-HW-3QJ" secondAttribute="bottom" constant="15" id="TZb-uR-n12"/> |
| | | <constraint firstItem="yrU-ab-vv9" firstAttribute="leading" secondItem="3V0-GL-Fmn" secondAttribute="leading" constant="14" id="bvf-qv-PXf"/> |
| | | <constraint firstItem="LtS-Mg-aeT" firstAttribute="leading" secondItem="yrU-ab-vv9" secondAttribute="trailing" id="ce9-HT-eYR"/> |
| | | <constraint firstItem="yrU-ab-vv9" firstAttribute="top" secondItem="HQ8-qZ-zeA" secondAttribute="bottom" constant="10" id="fcu-Lq-OG7"/> |
| | | <constraint firstAttribute="trailing" secondItem="3WZ-Jf-leh" secondAttribute="trailing" constant="13" id="gDs-iU-l4D"/> |
| | | <constraint firstItem="HQ8-qZ-zeA" firstAttribute="top" secondItem="3V0-GL-Fmn" secondAttribute="top" id="gge-7H-yMR"/> |
| | | <constraint firstAttribute="trailing" secondItem="lUx-IV-YIU" secondAttribute="trailing" id="i5N-By-Pa9"/> |
| | | <constraint firstItem="ZOY-ws-sjP" firstAttribute="leading" secondItem="3V0-GL-Fmn" secondAttribute="leading" constant="14" id="k11-lO-F1N"/> |
| | | <constraint firstItem="SHM-HW-3QJ" firstAttribute="top" secondItem="PgE-zX-EIu" secondAttribute="bottom" constant="7" id="kjs-SE-QJz"/> |
| | | <constraint firstItem="3WZ-Jf-leh" firstAttribute="leading" secondItem="3V0-GL-Fmn" secondAttribute="leading" constant="13" id="msq-Yj-Hkl"/> |
| | | <constraint firstItem="PgE-zX-EIu" firstAttribute="top" secondItem="yrU-ab-vv9" secondAttribute="bottom" constant="7" id="tro-c3-NxF"/> |
| | | <constraint firstItem="PgE-zX-EIu" firstAttribute="leading" secondItem="3V0-GL-Fmn" secondAttribute="leading" constant="14" id="upN-6F-Xy0"/> |
| | | <constraint firstAttribute="bottom" secondItem="ZOY-ws-sjP" secondAttribute="bottom" constant="10" id="x2O-1I-fif"/> |
| | | <constraint firstAttribute="trailing" secondItem="HQ8-qZ-zeA" secondAttribute="trailing" id="xc1-2D-IN1"/> |
| | | <constraint firstAttribute="trailing" secondItem="ZOY-ws-sjP" secondAttribute="trailing" constant="14" id="zdu-6P-uIG"/> |
| | | </constraints> |
| | | </view> |
| | |
| | | <resources> |
| | | <systemColor name="systemBackgroundColor"> |
| | | <color white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/> |
| | | </systemColor> |
| | | <systemColor name="systemGray5Color"> |
| | | <color red="0.89803921568627454" green="0.89803921568627454" blue="0.91764705882352937" alpha="1" colorSpace="custom" customColorSpace="sRGB"/> |
| | | </systemColor> |
| | | </resources> |
| | | </document> |
| | |
| | | |
| | | import UIKit |
| | | import RxRelay |
| | | |
| | | class MarketViewModel{ |
| | | var number = BehaviorRelay<Int>(value:1) |
| | | } |
| | | import QMUIKit |
| | | |
| | | class MarketExchangeVC: BaseVC { |
| | | @IBOutlet weak var scrollView: UIScrollView! |
| | |
| | | @IBOutlet weak var view_container: UIView! |
| | | @IBOutlet weak var field_number: UITextField! |
| | | @IBOutlet weak var cons_footerHei: NSLayoutConstraint! |
| | | @IBOutlet weak var label_address: UILabel! |
| | | @IBOutlet weak var label_address_info: UILabel! |
| | | @IBOutlet weak var img_cover: UIImageView! |
| | | @IBOutlet weak var label_goodsName: UILabel! |
| | | @IBOutlet weak var label_coin: UILabel! |
| | | @IBOutlet weak var btn_add: UIButton! |
| | | @IBOutlet weak var btn_reduce: UIButton! |
| | | @IBOutlet weak var textView_remark: QMUITextView! |
| | | @IBOutlet weak var label_num: UILabel! |
| | | @IBOutlet weak var label_needCoin: UILabel! |
| | | @IBOutlet weak var label_orderNum: UILabel! |
| | | @IBOutlet weak var label_footNeedCoin: UILabel! |
| | | |
| | | private var viewModel = MarketViewModel() |
| | | private var viewModel = MarketContentViewModel() |
| | | |
| | | required init(viewModel:MarketContentViewModel) { |
| | | super.init(nibName: nil, bundle: nil) |
| | | self.viewModel = viewModel |
| | | } |
| | | |
| | | required init?(coder: NSCoder) { |
| | | fatalError("init(coder:) has not been implemented") |
| | | } |
| | | |
| | | override func viewDidLoad() { |
| | | super.viewDidLoad() |
| | | |
| | | Services.redeemNow(goodId: viewModel.detailModel.value!.good!.id).subscribe(onNext: {result in |
| | | self.label_orderNum.text = result.data?.orderNumber ?? "" |
| | | self.viewModel.detailModel.accept(result.data) |
| | | }).disposed(by: disposeBag) |
| | | |
| | | Services.addressList().subscribe(onNext: {[weak self]result in |
| | | self?.viewModel.address.accept(result.data ?? []) |
| | | if let first = result.data?.filter({$0.isDefault == 1}).first{ |
| | | self?.label_address.text = first.address |
| | | self?.label_address_info.text = first.recipient + "|" + first.recipientPhone |
| | | }else{ |
| | | self?.label_address.text = "新建收货地址" |
| | | self?.label_address_info.isHidden = true |
| | | } |
| | | }).disposed(by: disposeBag) |
| | | |
| | | self.img_cover.sd_setImage(with: URL(string: viewModel.detailModel.value?.good?.coverImg)) |
| | | self.label_goodsName.text = viewModel.detailModel.value?.good?.name ?? "" |
| | | self.label_coin.text = "\(viewModel.detailModel.value?.good?.integral ?? 0)" |
| | | if viewModel.detailModel.value?.good?.userCount == 1{ |
| | | btn_add.isEnabled = false |
| | | btn_reduce.isEnabled = false |
| | | field_number.isEnabled = false |
| | | } |
| | | } |
| | | |
| | | override func setUI() { |
| | |
| | | override func setRx() { |
| | | viewModel.number.subscribe(onNext: {[weak self] num in |
| | | self?.field_number.text = "\(num)" |
| | | self?.label_num.text = "\(num)" |
| | | let totalCoin = num * (self?.viewModel.detailModel.value?.good?.integral ?? 0) |
| | | self?.label_needCoin.text = "\(totalCoin)" |
| | | self?.label_footNeedCoin.text = "\(totalCoin)" |
| | | }).disposed(by: disposeBag) |
| | | } |
| | | |
| | | |
| | | @IBAction func addressAction(_ sender: Any) { |
| | | if viewModel.address.value.filter({$0.isDefault == 1}).count > 0{ |
| | | let vc = AddressManageVC(type: .choose) |
| | | vc.title = "地址管理" |
| | | push(vc: vc) |
| | | }else{ |
| | | let vc = AddressManageVC(type: .handle) |
| | | vc.title = "地址管理" |
| | | push(vc: vc) |
| | | } |
| | | } |
| | | |
| | | @IBAction func addNumAction(_ sender: UIButton) { |
| | | let num = viewModel.number.value + 1 |
| | | var num = viewModel.number.value + 1 |
| | | if num >= viewModel.detailModel.value?.good?.userCount ?? 0{ |
| | | num = viewModel.detailModel.value?.good?.userCount ?? 0 |
| | | sender.isEnabled = false |
| | | } |
| | | viewModel.number.accept(num) |
| | | } |
| | | |
| | | @IBAction func reduceAction(_ sender: UIButton) { |
| | | let num = max(1,viewModel.number.value - 1) |
| | | viewModel.number.accept(num) |
| | | btn_add.isEnabled = true |
| | | } |
| | | |
| | | @IBAction func exchangeAction(_ sender: UIButton) { |
| | | |
| | | guard viewModel.address.value.filter({$0.isDefault == 1}).count != 0 else{ |
| | | CommonAlertView.show(content: "请先设置收货地址") { |
| | | let vc = AddressManageVC(type: .handle) |
| | | vc.title = "地址管理" |
| | | self.push(vc: vc) |
| | | } |
| | | return |
| | | } |
| | | |
| | | CommonAlertView.show(content: "确认兑换当前商品吗?") { |
| | | let vc = ExchangeResultVC(resultType: .success) |
| | | vc.title = "商品详情" |
| | | self.push(vc: vc) |
| | | let goodsId = self.viewModel.detailModel.value!.good!.id |
| | | let num = self.viewModel.number.value |
| | | let orderNumber = self.viewModel.detailModel.value?.orderNumber ?? "" |
| | | let recipientId = self.viewModel.detailModel.value?.recipient?.id ?? 0 |
| | | |
| | | Services.goodsExchangeStudy(goodsId: goodsId, number: num, orderNumber: orderNumber, recipientId: recipientId, remark: self.textView_remark.text!).subscribe(onNext: {_ in |
| | | let vc = ExchangeResultVC(resultType: .success) |
| | | vc.title = "商品详情" |
| | | self.push(vc: vc) |
| | | }).disposed(by: self.disposeBag) |
| | | } |
| | | } |
| | | } |
| | |
| | | <objects> |
| | | <placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner" customClass="MarketExchangeVC" customModule="DolphinEnglishLearnStudent" customModuleProvider="target"> |
| | | <connections> |
| | | <outlet property="btn_add" destination="wqg-IO-Jti" id="tqa-wd-rR2"/> |
| | | <outlet property="btn_reduce" destination="H9G-ck-ezM" id="uPJ-2M-QEo"/> |
| | | <outlet property="cons_footerHei" destination="71z-Eh-Ya8" id="V0f-Rh-ggi"/> |
| | | <outlet property="field_number" destination="1nG-XY-fwB" id="xye-yR-VBc"/> |
| | | <outlet property="img_cover" destination="QM5-dP-No2" id="xux-xq-ol5"/> |
| | | <outlet property="label_address" destination="ph9-Ra-CxP" id="b0j-bK-UQV"/> |
| | | <outlet property="label_address_info" destination="Hns-QV-baw" id="v5s-wf-nHN"/> |
| | | <outlet property="label_coin" destination="Zy6-3Q-Lgi" id="WNc-y4-9Yn"/> |
| | | <outlet property="label_footNeedCoin" destination="Nka-ZK-eeP" id="1wN-Kd-xoF"/> |
| | | <outlet property="label_goodsName" destination="SZF-J0-byW" id="bMb-RR-rHM"/> |
| | | <outlet property="label_needCoin" destination="vFF-je-HEk" id="XDA-D5-HO1"/> |
| | | <outlet property="label_num" destination="p4X-ju-9r7" id="Cmx-HF-NKT"/> |
| | | <outlet property="label_orderNum" destination="BaU-rt-9wh" id="fwg-Lq-bZB"/> |
| | | <outlet property="scrollView" destination="hFz-gY-osL" id="xXh-5z-6XE"/> |
| | | <outlet property="textView_remark" destination="Rq2-vc-D0Q" id="sDq-vQ-gM6"/> |
| | | <outlet property="view" destination="i5M-Pr-FkT" id="sfx-zR-JGt"/> |
| | | <outlet property="view_container" destination="4wG-oJ-eBG" id="8U4-Q9-4Ap"/> |
| | | <outlet property="view_footer" destination="d3o-Ba-FIK" id="EMz-WT-ojz"/> |
| | |
| | | <stackView opaque="NO" contentMode="scaleToFill" axis="vertical" translatesAutoresizingMaskIntoConstraints="NO" id="HCf-Ym-o1O"> |
| | | <rect key="frame" x="0.0" y="0.0" width="556" height="600"/> |
| | | <subviews> |
| | | <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="sfn-3Q-b7V"> |
| | | <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="sfn-3Q-b7V" customClass="TapBtn" customModule="DolphinEnglishLearnStudent" customModuleProvider="target"> |
| | | <rect key="frame" x="0.0" y="0.0" width="556" height="90"/> |
| | | <subviews> |
| | | <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="5h7-8X-cXI"> |
| | |
| | | <constraint firstAttribute="height" constant="3" id="7Bs-Y1-RKJ"/> |
| | | </constraints> |
| | | </view> |
| | | <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Label" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="ph9-Ra-CxP"> |
| | | <rect key="frame" x="14" y="28" width="492" height="20"/> |
| | | <constraints> |
| | | <constraint firstAttribute="height" constant="20" id="cgw-w2-dsN"/> |
| | | </constraints> |
| | | <fontDescription key="fontDescription" type="system" weight="medium" pointSize="14"/> |
| | | <color key="textColor" red="0.011764705882352941" green="0.015686274509803921" blue="0.019607843137254902" alpha="1" colorSpace="custom" customColorSpace="sRGB"/> |
| | | <nil key="highlightedColor"/> |
| | | </label> |
| | | <imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="icon_more_gray" translatesAutoresizingMaskIntoConstraints="NO" id="jKh-8m-ogE"> |
| | | <rect key="frame" x="536" y="40" width="6" height="10"/> |
| | | </imageView> |
| | | <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Label" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Hns-QV-baw"> |
| | | <rect key="frame" x="14" y="53" width="492" height="14.5"/> |
| | | <fontDescription key="fontDescription" type="system" pointSize="12"/> |
| | | <nil key="textColor"/> |
| | | <nil key="highlightedColor"/> |
| | | </label> |
| | | <stackView opaque="NO" contentMode="scaleToFill" axis="vertical" spacing="5" translatesAutoresizingMaskIntoConstraints="NO" id="ZAd-Ha-PgP"> |
| | | <rect key="frame" x="14" y="25.5" width="36" height="39.5"/> |
| | | <subviews> |
| | | <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Label" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="ph9-Ra-CxP"> |
| | | <rect key="frame" x="0.0" y="0.0" width="36" height="20"/> |
| | | <constraints> |
| | | <constraint firstAttribute="height" constant="20" id="cgw-w2-dsN"/> |
| | | </constraints> |
| | | <fontDescription key="fontDescription" type="system" weight="medium" pointSize="14"/> |
| | | <color key="textColor" red="0.011764705882352941" green="0.015686274509803921" blue="0.019607843137254902" alpha="1" colorSpace="custom" customColorSpace="sRGB"/> |
| | | <nil key="highlightedColor"/> |
| | | </label> |
| | | <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Label" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Hns-QV-baw"> |
| | | <rect key="frame" x="0.0" y="25" width="36" height="14.5"/> |
| | | <fontDescription key="fontDescription" type="system" pointSize="12"/> |
| | | <nil key="textColor"/> |
| | | <nil key="highlightedColor"/> |
| | | </label> |
| | | </subviews> |
| | | </stackView> |
| | | </subviews> |
| | | <constraints> |
| | | <constraint firstItem="jKh-8m-ogE" firstAttribute="centerY" secondItem="sfn-3Q-b7V" secondAttribute="centerY" id="AIT-eX-UYg"/> |
| | | <constraint firstAttribute="trailing" secondItem="5h7-8X-cXI" secondAttribute="trailing" id="Byx-At-ZHn"/> |
| | | <constraint firstAttribute="height" constant="90" id="Gtx-jC-H0V"/> |
| | | <constraint firstItem="ph9-Ra-CxP" firstAttribute="leading" secondItem="sfn-3Q-b7V" secondAttribute="leading" constant="14" id="L6f-uW-gIs"/> |
| | | <constraint firstItem="ph9-Ra-CxP" firstAttribute="top" secondItem="sfn-3Q-b7V" secondAttribute="top" constant="28" id="Pzt-wT-2Uz"/> |
| | | <constraint firstItem="ZAd-Ha-PgP" firstAttribute="leading" secondItem="sfn-3Q-b7V" secondAttribute="leading" constant="14" id="KKV-Kz-UZ6"/> |
| | | <constraint firstAttribute="bottom" secondItem="5h7-8X-cXI" secondAttribute="bottom" id="dS7-Gn-QOD"/> |
| | | <constraint firstAttribute="trailing" secondItem="jKh-8m-ogE" secondAttribute="trailing" constant="14" id="fpD-Vw-mh2"/> |
| | | <constraint firstItem="5h7-8X-cXI" firstAttribute="leading" secondItem="sfn-3Q-b7V" secondAttribute="leading" id="g86-ED-gAW"/> |
| | | <constraint firstItem="Hns-QV-baw" firstAttribute="trailing" secondItem="ph9-Ra-CxP" secondAttribute="trailing" id="hFX-F5-1NJ"/> |
| | | <constraint firstItem="Hns-QV-baw" firstAttribute="leading" secondItem="ph9-Ra-CxP" secondAttribute="leading" id="l9W-26-0ij"/> |
| | | <constraint firstItem="Hns-QV-baw" firstAttribute="top" secondItem="ph9-Ra-CxP" secondAttribute="bottom" constant="5" id="mta-MA-VXe"/> |
| | | <constraint firstAttribute="trailing" secondItem="ph9-Ra-CxP" secondAttribute="trailing" constant="50" id="oe6-gk-huK"/> |
| | | <constraint firstAttribute="trailing" secondItem="jKh-8m-ogE" secondAttribute="trailing" constant="14" id="on7-ez-QYT"/> |
| | | <constraint firstItem="ZAd-Ha-PgP" firstAttribute="centerY" secondItem="sfn-3Q-b7V" secondAttribute="centerY" id="qhc-bm-AqF"/> |
| | | </constraints> |
| | | <connections> |
| | | <action selector="addressAction:" destination="-1" eventType="touchUpInside" id="fj4-mV-Wor"/> |
| | | </connections> |
| | | </view> |
| | | <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="Pcy-2J-bsd"> |
| | | <rect key="frame" x="0.0" y="90" width="556" height="366"/> |
| | | <subviews> |
| | | <imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="QM5-dP-No2"> |
| | | <imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="QM5-dP-No2"> |
| | | <rect key="frame" x="14" y="15" width="170" height="170"/> |
| | | <constraints> |
| | | <constraint firstAttribute="width" constant="170" id="gTg-aH-0dy"/> |
| | |
| | | <action selector="addNumAction:" destination="-1" eventType="touchUpInside" id="N9f-5O-JZz"/> |
| | | </connections> |
| | | </button> |
| | | <button opaque="NO" contentMode="scaleToFill" fixedFrame="YES" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="H9G-ck-ezM"> |
| | | <rect key="frame" x="702" y="206" width="32" height="22"/> |
| | | <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/> |
| | | <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="H9G-ck-ezM"> |
| | | <rect key="frame" x="440" y="207" width="32" height="22"/> |
| | | <inset key="imageEdgeInsets" minX="0.0" minY="0.0" maxX="2.2250738585072014e-308" maxY="0.0"/> |
| | | <state key="normal" image="btn_reduce"/> |
| | | <state key="disabled" image="btn_reduce_un"/> |
| | |
| | | <color key="backgroundColor" systemColor="systemBackgroundColor"/> |
| | | <constraints> |
| | | <constraint firstAttribute="trailing" secondItem="SZF-J0-byW" secondAttribute="trailing" constant="13" id="2bc-jD-0jQ"/> |
| | | <constraint firstItem="Y1j-mH-7vJ" firstAttribute="centerY" secondItem="H9G-ck-ezM" secondAttribute="centerY" id="3fZ-cn-vBb"/> |
| | | <constraint firstItem="QM5-dP-No2" firstAttribute="top" secondItem="Pcy-2J-bsd" secondAttribute="top" constant="15" id="3oV-je-E0W"/> |
| | | <constraint firstItem="SZF-J0-byW" firstAttribute="leading" secondItem="QM5-dP-No2" secondAttribute="trailing" constant="13" id="4nD-DW-K4G"/> |
| | | <constraint firstItem="wqg-IO-Jti" firstAttribute="leading" secondItem="Y1j-mH-7vJ" secondAttribute="trailing" id="96J-NH-U7L"/> |
| | | <constraint firstItem="MS7-3T-DWG" firstAttribute="top" secondItem="EeU-Wx-jBI" secondAttribute="bottom" constant="17" id="APQ-K4-sOj"/> |
| | | <constraint firstAttribute="trailing" secondItem="xEk-ac-udO" secondAttribute="trailing" constant="14" id="AaJ-eg-xRI"/> |
| | | <constraint firstItem="wqg-IO-Jti" firstAttribute="height" secondItem="H9G-ck-ezM" secondAttribute="height" id="BxV-pF-PDX"/> |
| | | <constraint firstAttribute="trailing" secondItem="Y1j-mH-7vJ" secondAttribute="trailing" constant="42" id="Cnz-nI-ucx"/> |
| | | <constraint firstItem="xEk-ac-udO" firstAttribute="leading" secondItem="Pcy-2J-bsd" secondAttribute="leading" constant="12" id="DSj-62-NMj"/> |
| | | <constraint firstItem="MS7-3T-DWG" firstAttribute="leading" secondItem="EeU-Wx-jBI" secondAttribute="leading" id="EM3-jV-CSR"/> |
| | |
| | | <constraint firstItem="Y1j-mH-7vJ" firstAttribute="top" secondItem="h4B-Ju-L2P" secondAttribute="bottom" constant="22" id="RcG-f4-yEi"/> |
| | | <constraint firstItem="h4B-Ju-L2P" firstAttribute="centerY" secondItem="Zy6-3Q-Lgi" secondAttribute="centerY" id="ScA-Kv-FAY"/> |
| | | <constraint firstItem="xEk-ac-udO" firstAttribute="top" secondItem="5zn-TC-ZAu" secondAttribute="bottom" constant="14" id="TRf-HU-Y0g"/> |
| | | <constraint firstItem="wqg-IO-Jti" firstAttribute="width" secondItem="H9G-ck-ezM" secondAttribute="width" id="TaG-sx-WqG"/> |
| | | <constraint firstAttribute="trailing" secondItem="5zn-TC-ZAu" secondAttribute="trailing" constant="14" id="XsR-S7-5se"/> |
| | | <constraint firstItem="h4B-Ju-L2P" firstAttribute="leading" secondItem="Zy6-3Q-Lgi" secondAttribute="trailing" id="XyT-7a-Pzk"/> |
| | | <constraint firstItem="5zn-TC-ZAu" firstAttribute="top" secondItem="MS7-3T-DWG" secondAttribute="bottom" constant="12" id="Zb6-DZ-qrC"/> |
| | |
| | | <constraint firstItem="EeU-Wx-jBI" firstAttribute="top" secondItem="QM5-dP-No2" secondAttribute="bottom" constant="18" id="kWP-Z3-Uve"/> |
| | | <constraint firstItem="QM5-dP-No2" firstAttribute="leading" secondItem="Pcy-2J-bsd" secondAttribute="leading" constant="14" id="lJI-a1-yyL"/> |
| | | <constraint firstItem="EeU-Wx-jBI" firstAttribute="leading" secondItem="Pcy-2J-bsd" secondAttribute="leading" constant="14" id="pIg-OO-tpF"/> |
| | | <constraint firstItem="Y1j-mH-7vJ" firstAttribute="leading" secondItem="H9G-ck-ezM" secondAttribute="trailing" id="v1W-TC-i1N"/> |
| | | <constraint firstItem="h4B-Ju-L2P" firstAttribute="bottom" secondItem="QM5-dP-No2" secondAttribute="bottom" id="z2m-b7-4WH"/> |
| | | </constraints> |
| | | </view> |
| | |
| | | @IBOutlet weak var btn_exchangeRecord: QMUIButton! |
| | | @IBOutlet weak var btn_share: QMUIButton! |
| | | @IBOutlet weak var btn_etudyRecord: QMUIButton! |
| | | |
| | | @IBOutlet weak var imge_cover: UIImageView! |
| | | @IBOutlet weak var label_name: UILabel! |
| | | @IBOutlet weak var label_info: UILabel! |
| | | |
| | | override func viewDidLoad() { |
| | | super.viewDidLoad() |
| | | |
| | | // Do any additional setup after loading the view. |
| | | Services.userInfo().subscribe(onNext: {result in |
| | | if let model = result.data{ |
| | | self.imge_cover.sd_setImage(with: URL(string: model.headImg)) |
| | | self.label_name.text = model.name |
| | | // var items = Array<String>() |
| | | // items.append("剩余积分:\(model.integral)") |
| | | // items.append("学习进度:\(model.integral)") |
| | | } |
| | | }).disposed(by: disposeBag) |
| | | } |
| | | |
| | | |
| | |
| | | |
| | | @IBAction func quitAction(_ sender: UIButton) { |
| | | CommonAlertView.show(content: "确认退出当前账户吗?") { |
| | | |
| | | Services.logoutStudy().subscribe(onNext: {result in |
| | | sceneDelegate?.needLogin() |
| | | }).disposed(by: self.disposeBag) |
| | | } |
| | | } |
| | | } |
| | |
| | | <outlet property="btn_etudyRecord" destination="0pk-gO-3Qh" id="SeS-bo-pn4"/> |
| | | <outlet property="btn_exchangeRecord" destination="uH5-eT-V9Z" id="8gd-zT-JND"/> |
| | | <outlet property="btn_share" destination="gtG-mF-MKi" id="ejw-y9-ugq"/> |
| | | <outlet property="imge_cover" destination="qXF-FL-HEr" id="fG7-3a-cHy"/> |
| | | <outlet property="label_info" destination="LJb-Ki-p3S" id="88F-Ay-1nv"/> |
| | | <outlet property="label_name" destination="D0d-O7-Pt2" id="C7j-gd-GwB"/> |
| | | <outlet property="view" destination="i5M-Pr-FkT" id="sfx-zR-JGt"/> |
| | | </connections> |
| | | </placeholder> |
| | |
| | | // |
| | | |
| | | import UIKit |
| | | import RxSwift |
| | | |
| | | class AddressManageTCell: UITableViewCell { |
| | | |
| | |
| | | @IBOutlet weak var btn_delete: UIButton! |
| | | @IBOutlet weak var btn_edit: UIButton! |
| | | @IBOutlet weak var img_more: UIImageView! |
| | | |
| | | @IBOutlet weak var label_address: UILabel! |
| | | @IBOutlet weak var label_addressInfo: UILabel! |
| | | |
| | | private var disposeBag = DisposeBag() |
| | | |
| | | var addressModel:AddressModel!{ |
| | | didSet{ |
| | | label_address.text = addressModel.address |
| | | label_addressInfo.text = addressModel.recipient + "|" + addressModel.recipientPhone |
| | | isDefault(addressModel.isDefault == 1) |
| | | } |
| | | } |
| | | |
| | | override func awakeFromNib() { |
| | | super.awakeFromNib() |
| | | selectionStyle = .none |
| | |
| | | |
| | | func isDefault(_ state:Bool){ |
| | | if state{ |
| | | |
| | | let attribute = AttributedStringbuilder.build().add(string:" 默认 ", withFont: .systemFont(ofSize: 14, weight: .medium), withColor: UIColor.white).mutableAttributedString |
| | | btn_default.setAttributedTitle(attribute, for: .normal) |
| | | |
| | | btn_default.setTitle(" 默认 ", for: .normal) |
| | | btn_default.backgroundColor = UIColor(hexStr: "#F7462D") |
| | | btn_default.setTitleColor(.white, for: .normal) |
| | |
| | | } |
| | | |
| | | @IBAction func deleteAction(_ sender: UIButton) { |
| | | CommonAlertView.show(content:"确认删除所选信息吗?") { |
| | | |
| | | CommonAlertView.show(content:"确认删除所选信息吗?") {[weak self] () in |
| | | guard let weakSelf = self else { return } |
| | | Services.deleteAddress(id: weakSelf.addressModel.id).subscribe(onNext: { _ in |
| | | NotificationCenter.default.post(name: AddressManage_Refresh_Noti, object: nil) |
| | | }).disposed(by: weakSelf.disposeBag) |
| | | } |
| | | } |
| | | |
| | | @IBAction func setDefaultAction(_ sender: UIButton) { |
| | | Services.setDefaultStudy(id: addressModel.id).subscribe(onNext: { _ in |
| | | NotificationCenter.default.post(name: AddressManage_Refresh_Noti, object: nil) |
| | | }).disposed(by: disposeBag) |
| | | } |
| | | |
| | | |
| | | @IBAction func editAction(_ sender: UIButton) { |
| | | let vc = AddressManageHandleVC() |
| | | let vc = AddressManageHandleVC(addressModel) |
| | | vc.title = "编辑地址" |
| | | JQ_currentViewController().jq_push(vc: vc) |
| | | } |
| | |
| | | contentView.jq_addCorners(corner: [.bottomLeft,.bottomLeft], radius: 10) |
| | | } |
| | | |
| | | if isFist && isLast{ |
| | | contentView.jq_addCorners(corner: .allCorners, radius: 10) |
| | | } |
| | | |
| | | } |
| | | } |
| | |
| | | <?xml version="1.0" encoding="UTF-8"?> |
| | | <document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="32700.99.1234" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES"> |
| | | <device id="retina6_12" orientation="portrait" appearance="light"/> |
| | | <device id="ipad10_9rounded" orientation="portrait" layout="fullscreen" appearance="light"/> |
| | | <dependencies> |
| | | <deployment identifier="iOS"/> |
| | | <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="22684"/> |
| | |
| | | <objects> |
| | | <placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner"/> |
| | | <placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/> |
| | | <tableViewCell contentMode="scaleToFill" selectionStyle="default" indentationWidth="10" rowHeight="95" id="KGk-i7-Jjw" customClass="AddressManageTCell" customModule="DolphinEnglishLearnManager" customModuleProvider="target"> |
| | | <tableViewCell contentMode="scaleToFill" selectionStyle="default" indentationWidth="10" rowHeight="95" id="KGk-i7-Jjw" customClass="AddressManageTCell" customModule="DolphinEnglishLearnStudent" customModuleProvider="target"> |
| | | <rect key="frame" x="0.0" y="0.0" width="447" height="95"/> |
| | | <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/> |
| | | <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="KGk-i7-Jjw" id="H2p-sc-9uM"> |
| | |
| | | <nil key="highlightedColor"/> |
| | | </label> |
| | | <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="ezc-re-P3r"> |
| | | <rect key="frame" x="375" y="18.666666666666668" width="58" height="17.000000000000004"/> |
| | | <rect key="frame" x="375" y="18.5" width="58" height="17"/> |
| | | <constraints> |
| | | <constraint firstAttribute="height" constant="17" id="0Kf-PA-7Or"/> |
| | | <constraint firstAttribute="width" relation="greaterThanOrEqual" constant="42" id="4RT-3H-dH2"/> |
| | |
| | | <state key="normal" title="设为默认"> |
| | | <color key="titleColor" red="0.25490196079999999" green="0.63529411759999999" blue="0.92156862750000001" alpha="1" colorSpace="custom" customColorSpace="sRGB"/> |
| | | </state> |
| | | <connections> |
| | | <action selector="setDefaultAction:" destination="KGk-i7-Jjw" eventType="touchUpInside" id="p3w-8e-C9z"/> |
| | | </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="g9x-qe-0Me"> |
| | | <rect key="frame" x="13.999999999999996" y="42" width="41.666666666666657" height="17"/> |
| | | <rect key="frame" x="14" y="42" width="42" height="17"/> |
| | | <constraints> |
| | | <constraint firstAttribute="height" constant="17" id="04w-Er-l9A"/> |
| | | </constraints> |
| | |
| | | </connections> |
| | | </button> |
| | | <imageView hidden="YES" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="icon_more_gray" translatesAutoresizingMaskIntoConstraints="NO" id="Qav-bf-Mlo"> |
| | | <rect key="frame" x="427" y="42.666666666666664" width="6" height="10"/> |
| | | <rect key="frame" x="427" y="42.5" width="6" height="10"/> |
| | | </imageView> |
| | | </subviews> |
| | | <color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/> |
| | |
| | | <outlet property="btn_delete" destination="a8n-tE-gqa" id="elJ-VF-A4k"/> |
| | | <outlet property="btn_edit" destination="WFf-ch-GdK" id="Wfz-Oo-mbZ"/> |
| | | <outlet property="img_more" destination="Qav-bf-Mlo" id="ykH-wg-Brt"/> |
| | | <outlet property="label_address" destination="Qjx-I2-glv" id="iwX-fL-7LK"/> |
| | | <outlet property="label_addressInfo" destination="g9x-qe-0Me" id="cZT-hR-szg"/> |
| | | </connections> |
| | | <point key="canvasLocation" x="202.29007633587784" y="49.647887323943664"/> |
| | | </tableViewCell> |
| | |
| | | import UIKit |
| | | |
| | | class GoodsItemTCell: UITableViewCell { |
| | | |
| | | |
| | | @IBOutlet weak var label_state: UILabel! |
| | | @IBOutlet weak var label_goodsName: UILabel! |
| | | @IBOutlet weak var label_types: UILabel! |
| | | @IBOutlet weak var label_goodsNum: UILabel! |
| | | @IBOutlet weak var label_receiptInfo: UILabel! |
| | | @IBOutlet weak var label_sendInfo: UILabel! |
| | | @IBOutlet weak var btn_state: UIButton! |
| | | @IBOutlet weak var label_coin: UILabel! |
| | | |
| | | @IBOutlet weak var view_container: UIView! |
| | | override func awakeFromNib() { |
| | | super.awakeFromNib() |
| | |
| | | view_container.jq_addShadows(shadowColor: UIColor(hexStr: "#D9D9D9").withAlphaComponent(0.28), corner: 8, radius: 3, offset: CGSize(width: 0, height: 2), opacity: 1) |
| | | } |
| | | |
| | | func setModel(_ model:ExchangeRecordModel){ |
| | | label_goodsNum.text = "商品数量:\(model.count)" |
| | | label_coin.text = "\(model.integral)积分" |
| | | |
| | | var items_consignee = Array<String>() |
| | | items_consignee.append(model.consigneeName) |
| | | items_consignee.append(model.consigneePhone) |
| | | items_consignee.append(model.consigneeAddress) |
| | | label_receiptInfo.text = "收货信息:" + items_consignee.joined(separator: "|") |
| | | |
| | | var items_express = Array<String>() |
| | | items_express.append(model.express) |
| | | items_express.append(model.expressNumber) |
| | | |
| | | label_sendInfo.isHidden = items_express.filter({!$0.isEmpty}).count == 0 |
| | | label_sendInfo.text = "发货信息:" + items_express.joined(separator: "|") |
| | | } |
| | | |
| | | @IBAction func handleAction(_ sender: UIButton) { |
| | | let vc = AddressManageVC(type: .choose) |
| | | vc.title = "修改地址" |
| | |
| | | <?xml version="1.0" encoding="UTF-8"?> |
| | | <document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="32700.99.1234" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES"> |
| | | <device id="retina6_12" orientation="portrait" appearance="light"/> |
| | | <device id="ipad10_9rounded" orientation="portrait" layout="fullscreen" appearance="light"/> |
| | | <dependencies> |
| | | <deployment identifier="iOS"/> |
| | | <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="22684"/> |
| | |
| | | <objects> |
| | | <placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner"/> |
| | | <placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/> |
| | | <tableViewCell contentMode="scaleToFill" selectionStyle="default" indentationWidth="10" reuseIdentifier="_GoodsItemTCell" rowHeight="344" id="KGk-i7-Jjw" customClass="GoodsItemTCell" customModule="DolphinEnglishLearnManager" customModuleProvider="target"> |
| | | <tableViewCell contentMode="scaleToFill" selectionStyle="default" indentationWidth="10" reuseIdentifier="_GoodsItemTCell" rowHeight="344" id="KGk-i7-Jjw" customClass="GoodsItemTCell" customModule="DolphinEnglishLearnStudent" customModuleProvider="target"> |
| | | <rect key="frame" x="0.0" y="0.0" width="532" height="344"/> |
| | | <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/> |
| | | <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="KGk-i7-Jjw" id="H2p-sc-9uM"> |
| | |
| | | <rect key="frame" x="0.0" y="6" width="532" height="332"/> |
| | | <subviews> |
| | | <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Label" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="9oA-7x-in6"> |
| | | <rect key="frame" x="8" y="19" width="41.333333333333336" height="20.333333333333329"/> |
| | | <rect key="frame" x="8" y="19" width="41.5" height="20.5"/> |
| | | <fontDescription key="fontDescription" type="system" pointSize="17"/> |
| | | <nil key="textColor"/> |
| | | <nil key="highlightedColor"/> |
| | | </label> |
| | | <imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="HZS-Oe-5LR"> |
| | | <rect key="frame" x="8" y="52.333333333333343" width="148" height="148"/> |
| | | <rect key="frame" x="8" y="52.5" width="148" height="148"/> |
| | | <constraints> |
| | | <constraint firstAttribute="width" constant="148" id="D3I-iy-k6w"/> |
| | | <constraint firstAttribute="width" secondItem="HZS-Oe-5LR" secondAttribute="height" multiplier="1:1" id="YQJ-eG-71N"/> |
| | |
| | | </userDefinedRuntimeAttributes> |
| | | </imageView> |
| | | <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Label" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="UdI-oe-WSO"> |
| | | <rect key="frame" x="173" y="52.333333333333336" width="234" height="19.333333333333336"/> |
| | | <rect key="frame" x="173" y="52.5" width="234" height="19.5"/> |
| | | <fontDescription key="fontDescription" type="system" pointSize="16"/> |
| | | <color key="textColor" red="0.082352941176470587" green="0.086274509803921567" blue="0.094117647058823528" alpha="1" colorSpace="custom" customColorSpace="sRGB"/> |
| | | <nil key="highlightedColor"/> |
| | | </label> |
| | | <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="0积分" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="nMG-SO-H2Z"> |
| | | <rect key="frame" x="481" y="52.666666666666664" width="40" height="18.666666666666664"/> |
| | | <rect key="frame" x="481" y="53" width="40" height="19"/> |
| | | <fontDescription key="fontDescription" name="DINAlternate-Bold" family="DIN Alternate" pointSize="16"/> |
| | | <color key="textColor" red="0.96862745100000003" green="0.27450980390000002" blue="0.1764705882" alpha="1" colorSpace="custom" customColorSpace="sRGB"/> |
| | | <nil key="highlightedColor"/> |
| | | </label> |
| | | <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Label" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="viA-yT-ZWk"> |
| | | <rect key="frame" x="173" y="71.666666666666671" width="359" height="17"/> |
| | | <rect key="frame" x="173" y="72" width="359" height="17"/> |
| | | <fontDescription key="fontDescription" type="system" pointSize="14"/> |
| | | <nil key="textColor"/> |
| | | <nil key="highlightedColor"/> |
| | | </label> |
| | | <stackView opaque="NO" contentMode="scaleToFill" axis="vertical" distribution="fillEqually" spacing="5" translatesAutoresizingMaskIntoConstraints="NO" id="vd5-iK-Ujb"> |
| | | <rect key="frame" x="173" y="95.666666666666686" width="303" height="70"/> |
| | | <rect key="frame" x="173" y="96" width="303" height="70"/> |
| | | <subviews> |
| | | <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="商品数量:-" textAlignment="natural" lineBreakMode="tailTruncation" numberOfLines="2" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="PlF-D7-xZD"> |
| | | <rect key="frame" x="0.0" y="0.0" width="303" height="20"/> |
| | |
| | | <nil key="highlightedColor"/> |
| | | </label> |
| | | <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="发货信息:-" textAlignment="natural" lineBreakMode="tailTruncation" numberOfLines="2" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="cSS-lo-Yba"> |
| | | <rect key="frame" x="0.0" y="49.999999999999986" width="303" height="20"/> |
| | | <rect key="frame" x="0.0" y="50" width="303" height="20"/> |
| | | <constraints> |
| | | <constraint firstAttribute="height" constant="20" id="mDC-DF-Wc3"/> |
| | | </constraints> |
| | |
| | | </tableViewCellContentView> |
| | | <viewLayoutGuide key="safeArea" id="njF-e1-oar"/> |
| | | <connections> |
| | | <outlet property="btn_state" destination="xwt-lH-fyW" id="YNc-qk-0gB"/> |
| | | <outlet property="label_coin" destination="nMG-SO-H2Z" id="weP-sJ-QLG"/> |
| | | <outlet property="label_goodsName" destination="UdI-oe-WSO" id="o9d-iH-BCJ"/> |
| | | <outlet property="label_goodsNum" destination="PlF-D7-xZD" id="1mj-HF-LGA"/> |
| | | <outlet property="label_receiptInfo" destination="qnF-SM-ngM" id="me5-fe-eW2"/> |
| | | <outlet property="label_sendInfo" destination="cSS-lo-Yba" id="4fa-fc-f69"/> |
| | | <outlet property="label_state" destination="9oA-7x-in6" id="lBa-OB-S8W"/> |
| | | <outlet property="label_types" destination="viA-yT-ZWk" id="3dU-h2-97f"/> |
| | | <outlet property="view_container" destination="EWl-m5-3O9" id="vyU-l1-0CY"/> |
| | | </connections> |
| | | <point key="canvasLocation" x="259.5419847328244" y="126.05633802816902"/> |
| | |
| | | |
| | | class Home_1_TCell: UITableViewCell { |
| | | |
| | | @IBOutlet weak var label_1: UILabel! |
| | | @IBOutlet weak var label_2: UILabel! |
| | | @IBOutlet weak var label_3: UILabel! |
| | | @IBOutlet weak var label_4: UILabel! |
| | | |
| | | var integralModel:IntegralModel!{ |
| | | didSet{ |
| | | label_1.text = integralModel.createTime |
| | | label_2.text = integralModel.integral |
| | | label_3.text = integralModel.method |
| | | label_4.text = integralModel.type |
| | | } |
| | | } |
| | | |
| | | var studyGamesRecordModel:StudyGamesRecordModel!{ |
| | | didSet{ |
| | | |
| | | } |
| | | } |
| | | |
| | | override func awakeFromNib() { |
| | | super.awakeFromNib() |
| | | selectionStyle = .none |
| | |
| | | <?xml version="1.0" encoding="UTF-8"?> |
| | | <document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="32700.99.1234" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES"> |
| | | <device id="retina6_12" orientation="portrait" appearance="light"/> |
| | | <device id="ipad10_9rounded" orientation="portrait" layout="fullscreen" appearance="light"/> |
| | | <dependencies> |
| | | <deployment identifier="iOS"/> |
| | | <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="22684"/> |
| | |
| | | <objects> |
| | | <placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner"/> |
| | | <placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/> |
| | | <tableViewCell contentMode="scaleToFill" selectionStyle="default" indentationWidth="10" reuseIdentifier="_Home_1_TCell" id="KGk-i7-Jjw" customClass="Home_1_TCell" customModule="DolphinEnglishLearnManager" customModuleProvider="target"> |
| | | <tableViewCell contentMode="scaleToFill" selectionStyle="default" indentationWidth="10" reuseIdentifier="_Home_1_TCell" id="KGk-i7-Jjw" customClass="Home_1_TCell" customModule="DolphinEnglishLearnStudent" customModuleProvider="target"> |
| | | <rect key="frame" x="0.0" y="0.0" width="320" height="44"/> |
| | | <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/> |
| | | <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="KGk-i7-Jjw" id="H2p-sc-9uM"> |
| | |
| | | <constraint firstItem="xga-Br-Izz" firstAttribute="top" secondItem="H2p-sc-9uM" secondAttribute="top" id="dHd-ao-jYA"/> |
| | | </constraints> |
| | | </tableViewCellContentView> |
| | | <connections> |
| | | <outlet property="label_1" destination="LLg-mN-hnD" id="7UE-le-ZJZ"/> |
| | | <outlet property="label_2" destination="bXA-iA-Sgc" id="4He-VH-alj"/> |
| | | <outlet property="label_3" destination="tft-ra-5If" id="CLY-lE-hEm"/> |
| | | <outlet property="label_4" destination="UQ2-uJ-GO9" id="nNZ-Gp-UJ9"/> |
| | | </connections> |
| | | <point key="canvasLocation" x="139" y="21"/> |
| | | </tableViewCell> |
| | | </objects> |
| | |
| | | // |
| | | |
| | | import UIKit |
| | | import QMUIKit |
| | | import RxRelay |
| | | |
| | | class AddressManageHandleViewModel{ |
| | | var userName = BehaviorRelay<String?>(value: nil) |
| | | var phone = BehaviorRelay<String?>(value: nil) |
| | | var provinceModel = BehaviorRelay<AddressTreeModel?>(value: nil) |
| | | var cityModel = BehaviorRelay<AddressTreeModel?>(value: nil) |
| | | var countryModel = BehaviorRelay<AddressTreeModel?>(value: nil) |
| | | var detailAddress = BehaviorRelay<String?>(value: nil) |
| | | var isDefault = BehaviorRelay<Bool>(value: false) |
| | | } |
| | | |
| | | class AddressManageHandleVC: BaseVC { |
| | | |
| | | @IBOutlet weak var tf_name: UITextField! |
| | | @IBOutlet weak var tf_phone: QMUITextField! |
| | | @IBOutlet weak var tf_address: QMUITextField! |
| | | @IBOutlet weak var tf_addressContent: QMUITextField! |
| | | @IBOutlet weak var btn_isDefault: UIButton! |
| | | |
| | | let viewModel = AddressManageHandleViewModel() |
| | | private var updateModel:AddressModel? |
| | | |
| | | @IBOutlet weak var view_container: UIView! |
| | | override func viewDidLoad() { |
| | | super.viewDidLoad() |
| | | |
| | | if let updateModel{ |
| | | tf_name.text = updateModel.recipient |
| | | tf_phone.text = updateModel.recipientPhone |
| | | tf_address.text = updateModel.province + updateModel.city |
| | | tf_addressContent.text = updateModel.address |
| | | btn_isDefault.isSelected = updateModel.isDefault == 1 |
| | | |
| | | viewModel.userName.accept(updateModel.recipient) |
| | | viewModel.phone.accept(updateModel.recipientPhone) |
| | | viewModel.detailAddress.accept(updateModel.address) |
| | | |
| | | viewModel.provinceModel.accept(AddressTreeModel(id: 0, name: updateModel.province, code: updateModel.provinceCode, parentId: 0, children: nil)) |
| | | viewModel.cityModel.accept(AddressTreeModel(id: 0, name: updateModel.city, code: updateModel.cityCode, parentId: 0, children: nil)) |
| | | } |
| | | } |
| | | |
| | | init(_ updateModel:AddressModel? = nil) { |
| | | super.init(nibName: nil, bundle: nil) |
| | | self.updateModel = updateModel |
| | | } |
| | | |
| | | required init?(coder: NSCoder) { |
| | | fatalError("init(coder:) has not been implemented") |
| | | } |
| | | |
| | | override func setUI() { |
| | | super.setUI() |
| | | view_container.jq_addShadows(shadowColor: UIColor(hexStr: "#D9D9D9").withAlphaComponent(0.28), corner: 8, radius: 20, offset: CGSize(width: 0, height: 2), opacity: 1) |
| | | tf_address.delegate = self |
| | | } |
| | | |
| | | override func setRx() { |
| | | tf_name.rx.text.bind(to: viewModel.userName).disposed(by: disposeBag) |
| | | tf_phone.rx.text.bind(to: viewModel.phone).disposed(by: disposeBag) |
| | | tf_addressContent.rx.text.bind(to: viewModel.detailAddress).disposed(by: disposeBag) |
| | | } |
| | | |
| | | @IBAction func chooseDefaultAction(_ sender: UIButton) { |
| | | sender.isSelected = !sender.isSelected |
| | | } |
| | | |
| | | @IBAction func saveAction(_ sender: UIButton) { |
| | | guard !(viewModel.userName.value?.isEmpty ?? true) else { |
| | | alert(msg: "请输入收件人姓名");return |
| | | } |
| | | |
| | | guard !(viewModel.phone.value?.isEmpty ?? true) else { |
| | | alert(msg: "请输入收件人电话");return |
| | | } |
| | | |
| | | guard viewModel.phone.value!.jq_isPhone else { |
| | | alert(msg: "请输入正确的手机号码");return |
| | | } |
| | | |
| | | guard viewModel.cityModel.value != nil else { |
| | | alert(msg: "请选择所在城市");return |
| | | } |
| | | |
| | | guard !(viewModel.detailAddress.value?.isEmpty ?? true) else { |
| | | alert(msg: "请输入详细地址");return |
| | | } |
| | | |
| | | Services.addressSaveOrUpdate(id: updateModel?.id, province: viewModel.provinceModel.value, city: viewModel.cityModel.value, country: nil, userName: viewModel.userName.value, userPhone: viewModel.phone.value, isDefault: btn_isDefault.isSelected, detailAddress: viewModel.detailAddress.value ?? "").subscribe(onNext: {_ in |
| | | if self.updateModel != nil{ |
| | | alertSuccess(msg: "编辑成功") |
| | | }else{ |
| | | alertSuccess(msg: "添加成功") |
| | | } |
| | | |
| | | self.navigationController?.popViewController() |
| | | NotificationCenter.default.post(name: AddressManage_Refresh_Noti, object: nil) |
| | | }).disposed(by: disposeBag) |
| | | } |
| | | } |
| | | |
| | | extension AddressManageHandleVC:QMUITextFieldDelegate{ |
| | | |
| | | func textFieldShouldBeginEditing(_ textField: UITextField) -> Bool { |
| | | CityAddressPickerView.show(title: "选择省市区") {[weak self] province, city, country in |
| | | self?.viewModel.provinceModel.accept(province) |
| | | self?.viewModel.cityModel.accept(city) |
| | | self?.viewModel.countryModel.accept(country) |
| | | |
| | | textField.text = "\(province?.name ?? "") \(city?.name ?? "") \(country?.name ?? "")" |
| | | } |
| | | return false |
| | | } |
| | | } |
| | |
| | | <objects> |
| | | <placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner" customClass="AddressManageHandleVC" customModule="DolphinEnglishLearnStudent" customModuleProvider="target"> |
| | | <connections> |
| | | <outlet property="btn_isDefault" destination="X5q-Za-IDi" id="6lr-qr-5nr"/> |
| | | <outlet property="tf_address" destination="FIR-Ti-oMo" id="XyJ-kk-oGH"/> |
| | | <outlet property="tf_addressContent" destination="9Rg-uR-zdR" id="sxn-jk-kYJ"/> |
| | | <outlet property="tf_name" destination="oWU-h5-9OT" id="9Gb-Hg-ka1"/> |
| | | <outlet property="tf_phone" destination="fLZ-09-hXt" id="YZs-at-Zeo"/> |
| | | <outlet property="view" destination="i5M-Pr-FkT" id="sfx-zR-JGt"/> |
| | | <outlet property="view_container" destination="qgb-Bj-4P0" id="eaY-Jn-MsE"/> |
| | | </connections> |
| | |
| | | <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="eNK-zb-eqQ"> |
| | | <rect key="frame" x="0.0" y="162" width="888" height="54"/> |
| | | <subviews> |
| | | <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="所在城市" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="uwd-8E-QFK"> |
| | | <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="详细地址" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="uwd-8E-QFK"> |
| | | <rect key="frame" x="14" y="18.5" width="57.5" height="17"/> |
| | | <fontDescription key="fontDescription" type="system" weight="medium" pointSize="14"/> |
| | | <nil key="textColor"/> |
| | |
| | | <color key="titleColor" red="0.0" green="0.0" blue="0.0" alpha="0.80000000000000004" colorSpace="custom" customColorSpace="sRGB"/> |
| | | </state> |
| | | <state key="selected" title="设为默认" image="btn_choose"/> |
| | | <connections> |
| | | <action selector="chooseDefaultAction:" destination="-1" eventType="touchUpInside" id="6aM-GW-eHa"/> |
| | | </connections> |
| | | </button> |
| | | </subviews> |
| | | <color key="backgroundColor" systemColor="systemBackgroundColor"/> |
| | |
| | | <real key="value" value="8"/> |
| | | </userDefinedRuntimeAttribute> |
| | | </userDefinedRuntimeAttributes> |
| | | <connections> |
| | | <action selector="saveAction:" destination="-1" eventType="touchUpInside" id="Ml0-tI-QPP"/> |
| | | </connections> |
| | | </button> |
| | | </subviews> |
| | | <viewLayoutGuide key="safeArea" id="fnl-2z-Ty3"/> |
| | |
| | | // |
| | | |
| | | import UIKit |
| | | import RxSwift |
| | | |
| | | let AddressManage_Refresh_Noti = Notification.Name.init("AddressManage_Refresh_Noti") |
| | | |
| | | class AddressManageViewModel:RefreshModel<AddressModel>{ |
| | | override func api() -> (Observable<BaseResponse<[AddressModel]>>)? { |
| | | Services.addressList() |
| | | } |
| | | } |
| | | |
| | | class AddressManageVC: BaseVC { |
| | | |
| | |
| | | |
| | | private var tableView:UITableView! |
| | | private var addressManageType:AddressManageType! |
| | | private var viewModel = AddressManageViewModel() |
| | | |
| | | required init(type:AddressManageType) { |
| | | super.init(nibName: nil, bundle: nil) |
| | |
| | | |
| | | override func viewDidLoad() { |
| | | super.viewDidLoad() |
| | | |
| | | viewModel.configure(tableView) |
| | | viewModel.beginRefresh() |
| | | } |
| | | |
| | | |
| | |
| | | } |
| | | } |
| | | |
| | | override func setRx() { |
| | | NotificationCenter.default.rx.notification(AddressManage_Refresh_Noti).take(until: self.rx.deallocated).subscribe(onNext: {[weak self] _ in |
| | | self?.viewModel.beginRefresh() |
| | | }).disposed(by: disposeBag) |
| | | } |
| | | |
| | | @objc func handleAction(){ |
| | | let vc = AddressManageHandleVC() |
| | | vc.title = "地址管理" |
| | |
| | | |
| | | extension AddressManageVC:UITableViewDataSource{ |
| | | func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { |
| | | let model = viewModel.dataSource.value[indexPath.row] |
| | | let cell = tableView.dequeueReusableCell(withIdentifier: "_AddressManageTCell") as! AddressManageTCell |
| | | cell.addressModel = model |
| | | cell.isFist = indexPath.row == 0 |
| | | cell.isLast = indexPath.row == 9 |
| | | cell.isDefault(indexPath.row == 0) |
| | | cell.isLast = indexPath.row == viewModel.dataSource.value.count - 1 |
| | | |
| | | cell.btn_edit.isHidden = addressManageType == .choose |
| | | cell.btn_delete.isHidden = addressManageType == .choose |
| | |
| | | } |
| | | |
| | | func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { |
| | | return 10 |
| | | return viewModel.dataSource.value.count |
| | | } |
| | | |
| | | func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat { |
| | |
| | | |
| | | import UIKit |
| | | import RxRelay |
| | | import JQTools |
| | | import RxSwift |
| | | |
| | | class CoinRecordHistoryViewModel{ |
| | | class CoinRecordHistoryViewModel:RefreshInnerModel<IntegralModel>{ |
| | | var selectDate = BehaviorRelay<Date?>(value:nil) |
| | | |
| | | override func api() -> (Observable<BaseResponse<BaseResponseList<IntegralModel>>>)? { |
| | | return Services.integralDetail(pageNum: page, time: selectDate.value?.jq_format("yyyy-MM")) |
| | | } |
| | | } |
| | | |
| | | class CoinRecordHistoryVC: BaseVC { |
| | |
| | | override func viewDidLoad() { |
| | | super.viewDidLoad() |
| | | |
| | | viewModel.configure(tableView,needMore: true) |
| | | viewModel.beginRefresh() |
| | | |
| | | Services.getIntegral().subscribe(onNext: {reault in |
| | | self.label_coin.text = "\(reault.data ?? 0)" |
| | | }).disposed(by: disposeBag) |
| | | } |
| | | |
| | | override func setUI() { |
| | |
| | | }).disposed(by: disposeBag) |
| | | } |
| | | |
| | | |
| | | @IBAction func chooseDateTimeAction(_ sender: UIButton) { |
| | | let year = viewModel.selectDate.value?.jq_nowYear() ?? Date().jq_nowYear() |
| | | let month = viewModel.selectDate.value?.jq_nowMonth() ?? Date().jq_nowMonth() |
| | | BitrhdayPickerView.show(title: "查询时间", type: .YM, defaultYear: year, defaultMonth: month, defaultDay: 0, minYear: 0) {[weak self] date in |
| | | self?.viewModel.selectDate.accept(date) |
| | | self?.viewModel.beginRefresh() |
| | | } |
| | | } |
| | | |
| | | @IBAction func resetAction(_ sender: UIButton) { |
| | | viewModel.selectDate.accept(nil) |
| | | btn_selectDate.setTitle("请选择", for: .normal) |
| | | viewModel.beginRefresh() |
| | | } |
| | | } |
| | | |
| | |
| | | cell.contentView.backgroundColor = .white |
| | | } |
| | | |
| | | let m = viewModel.dataSource.value?.records[indexPath.row] |
| | | cell.integralModel = m |
| | | return cell |
| | | } |
| | | |
| | | func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { |
| | | return 5 |
| | | return viewModel.dataSource.value?.records.count ?? 0 |
| | | } |
| | | |
| | | func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat { |
| | |
| | | </constraints> |
| | | <inset key="imageEdgeInsets" minX="0.0" minY="0.0" maxX="2.2250738585072014e-308" maxY="0.0"/> |
| | | <state key="normal" image="btn_refresh"/> |
| | | <connections> |
| | | <action selector="resetAction:" destination="-1" eventType="touchUpInside" id="UoC-8u-vu0"/> |
| | | </connections> |
| | | </button> |
| | | </subviews> |
| | | <constraints> |
| | |
| | | // |
| | | |
| | | import UIKit |
| | | import RxSwift |
| | | |
| | | class ExchangeRecordViewModel:RefreshModel<ExchangeRecordModel>{ |
| | | override func api() -> (Observable<BaseResponse<[ExchangeRecordModel]>>)? { |
| | | return Services.exchangeRecord() |
| | | } |
| | | } |
| | | |
| | | class ExchangeRecordHistoryVC: BaseVC { |
| | | |
| | | |
| | | private let viewModel = ExchangeRecordViewModel() |
| | | private var tableView:UITableView! |
| | | |
| | | override func viewDidLoad() { |
| | | super.viewDidLoad() |
| | | |
| | | viewModel.configure(tableView) |
| | | viewModel.beginRefresh() |
| | | } |
| | | |
| | | override func setUI() { |
| | |
| | | extension ExchangeRecordHistoryVC:UITableViewDataSource{ |
| | | func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { |
| | | let cell = tableView.dequeueReusableCell(withIdentifier: "_GoodsItemTCell") as! GoodsItemTCell |
| | | cell.setModel(viewModel.dataSource.value[indexPath.row]) |
| | | return cell |
| | | } |
| | | |
| | | func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { |
| | | return 10 |
| | | return viewModel.dataSource.value.count |
| | | } |
| | | |
| | | func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat { |
| | |
| | | @IBOutlet weak var view_menu: UIView! |
| | | @IBOutlet weak var tableView: UITableView! |
| | | |
| | | private var gamesRecordModel:StudyGamesModel?{ |
| | | didSet{ |
| | | self.tableView.reloadData() |
| | | } |
| | | } |
| | | |
| | | |
| | | override func viewDidLoad() { |
| | | super.viewDidLoad() |
| | | |
| | | Services.studyGamesRecord().subscribe(onNext: {result in |
| | | if let m = result.data{ |
| | | self.gamesRecordModel = m |
| | | } |
| | | }).disposed(by: disposeBag) |
| | | } |
| | | |
| | | override func setUI() { |
| | |
| | | }else{ |
| | | cell.contentView.backgroundColor = .white |
| | | } |
| | | if let m = gamesRecordModel?.gameRecordList[indexPath.row]{ |
| | | cell.studyGamesRecordModel = m |
| | | } |
| | | |
| | | |
| | | return cell |
| | | } |
| | | |
| | | func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { |
| | | return 5 |
| | | return gamesRecordModel?.gameRecordList.count ?? 0 |
| | | } |
| | | |
| | | func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat { |
| | |
| | | |
| | | class CommonWebVC: BaseVC { |
| | | |
| | | enum CommonWebType{ |
| | | case logoff |
| | | case userAgreement |
| | | case privacyAgreement |
| | | case userGuide |
| | | } |
| | | private var type:AgreementType! |
| | | |
| | | private var type:CommonWebType! |
| | | private lazy var webView:WKWebView = { |
| | | let webView = WKWebView() |
| | | webView.backgroundColor = .clear |
| | | webView.scrollView.backgroundColor = .clear |
| | | webView.isOpaque = false |
| | | return webView |
| | | }() |
| | | |
| | | init(type:CommonWebType) { |
| | | init(type:AgreementType) { |
| | | super.init(nibName: nil, bundle: nil) |
| | | self.type = type |
| | | } |
| | |
| | | override func setUI() { |
| | | super.setUI() |
| | | |
| | | view.addSubview(webView) |
| | | webView.snp.makeConstraints { make in |
| | | make.top.equalTo(self.view.safeAreaLayoutGuide.snp.top) |
| | | make.left.right.equalToSuperview() |
| | | make.bottom.equalTo(self.view.safeAreaLayoutGuide.snp.bottom) |
| | | } |
| | | |
| | | if type == .logoff{ |
| | | if type == .logout{ |
| | | let completeBtn = UIButton(type: .custom) |
| | | completeBtn.jq_cornerRadius = 8 |
| | | completeBtn.addTarget(self, action: #selector(handleAction), for: .touchUpInside) |
| | |
| | | }); |
| | | timer.resume() |
| | | } |
| | | |
| | | |
| | | Services.getAgreement(type: type).subscribe(onNext: {[weak self]content in |
| | | if let content = content.data{ |
| | | self?.webView.loadHTMLString(content.jq_wrapHtml(), baseURL: nil) |
| | | } |
| | | }).disposed(by: disposeBag) |
| | | } |
| | | |
| | | @objc func handleAction(sender:UIButton){ |
New file |
| | |
| | | // |
| | | // CityAddressPickerView.swift |
| | | // DolphinEnglishLearnStudent |
| | | // |
| | | // Created by 无故事王国 on 2024/6/3. |
| | | // |
| | | |
| | | import UIKit |
| | | import RxSwift |
| | | |
| | | class CityAddressPickerView: UIView { |
| | | |
| | | private var disposeBag = DisposeBag() |
| | | private var items = [AddressTreeModel]() |
| | | private var clouse:((AddressTreeModel?,AddressTreeModel?,AddressTreeModel?)->Void)! |
| | | |
| | | private var view_content:UIView = { |
| | | let v = UIView() |
| | | v.backgroundColor = .white |
| | | return v |
| | | }() |
| | | |
| | | private var label_title:UILabel = { |
| | | let label = UILabel() |
| | | label.font = .systemFont(ofSize: 18, weight: .medium) |
| | | label.textColor = .black.withAlphaComponent(0.8) |
| | | return label |
| | | }() |
| | | |
| | | private var btn_close:UIButton = { |
| | | let btn = UIButton(type: .custom) |
| | | btn.setImage(UIImage(named: "btn_close_circle"), for: .normal) |
| | | return btn |
| | | }() |
| | | |
| | | private var btn_complete:UIButton = { |
| | | let btn = UIButton(type: .custom) |
| | | btn.setTitle("确认", for: .normal) |
| | | btn.titleLabel?.font = UIFont.systemFont(ofSize: 14, weight: .medium) |
| | | btn.setTitleColor(.white, for: .normal) |
| | | btn.backgroundColor = Config.ThemeColor |
| | | btn.jq_cornerRadius = 8 |
| | | return btn |
| | | }() |
| | | |
| | | |
| | | private var picker:UIPickerView = { |
| | | let pickerView = UIPickerView() |
| | | return pickerView |
| | | }() |
| | | |
| | | |
| | | override init(frame: CGRect) { |
| | | super.init(frame: frame) |
| | | backgroundColor = UIColor.black.withAlphaComponent(0) |
| | | addSubview(view_content) |
| | | view_content.snp.makeConstraints { make in |
| | | make.left.right.equalToSuperview() |
| | | make.bottom.equalToSuperview().offset(JQ_ScreenW * 0.3278) |
| | | make.height.equalTo(JQ_ScreenW * 0.3278) |
| | | } |
| | | |
| | | |
| | | view_content.addSubview(btn_close) |
| | | btn_close.addTarget(self, action: #selector(closeAction), for: .touchUpInside) |
| | | btn_close.snp.makeConstraints { make in |
| | | make.top.equalTo(10) |
| | | make.right.equalTo(-11) |
| | | make.width.height.equalTo(23) |
| | | } |
| | | |
| | | view_content.addSubview(label_title) |
| | | label_title.snp.makeConstraints { make in |
| | | make.top.equalTo(30) |
| | | make.centerX.equalToSuperview() |
| | | make.height.equalTo(18) |
| | | } |
| | | |
| | | layoutIfNeeded() |
| | | } |
| | | |
| | | private func setUI(){ |
| | | var items = Array<String>() |
| | | items.append("省") |
| | | items.append("市") |
| | | items.append("区") |
| | | |
| | | let stackView = UIStackView() |
| | | stackView.axis = .horizontal |
| | | stackView.distribution = .fillEqually |
| | | stackView.spacing = 133 |
| | | view_content.addSubview(stackView) |
| | | stackView.snp.makeConstraints { make in |
| | | make.top.equalTo(label_title.snp.bottom).offset(27) |
| | | make.height.equalTo(25) |
| | | make.centerX.equalToSuperview() |
| | | } |
| | | |
| | | for (_,v) in items.enumerated(){ |
| | | let label = UILabel() |
| | | label.text = v |
| | | label.font = UIFont.systemFont(ofSize: 18, weight: .medium) |
| | | label.textColor = .black.withAlphaComponent(0.8) |
| | | label.textAlignment = .center |
| | | stackView.addArrangedSubview(label) |
| | | } |
| | | |
| | | view_content.addSubview(btn_complete) |
| | | btn_complete.snp.makeConstraints { make in |
| | | make.bottom.equalToSuperview().offset(-UIDevice.jq_safeEdges.bottom) |
| | | make.centerX.equalToSuperview() |
| | | make.width.equalTo(JQ_ScreenW * 0.1487) |
| | | make.height.equalTo(47) |
| | | } |
| | | |
| | | view_content.addSubview(picker) |
| | | picker.delegate = self |
| | | picker.dataSource = self |
| | | picker.snp.makeConstraints { make in |
| | | make.top.equalTo(label_title.snp.bottom).offset(50) |
| | | make.bottom.equalTo(btn_complete.snp.top) |
| | | make.centerX.equalToSuperview() |
| | | make.width.equalTo(500) |
| | | } |
| | | |
| | | btn_complete.addTarget(self, action: #selector(completeAction), for: .touchUpInside) |
| | | } |
| | | |
| | | required init?(coder: NSCoder) { |
| | | fatalError("init(coder:) has not been implemented") |
| | | } |
| | | |
| | | static func show(title:String,clouse:@escaping (AddressTreeModel?,AddressTreeModel?,AddressTreeModel?)->Void){ |
| | | let pickerView = CityAddressPickerView(frame: sceneDelegate?.window?.frame ?? .zero) |
| | | pickerView.clouse = clouse |
| | | sceneDelegate?.window?.addSubview(pickerView) |
| | | pickerView.setUI() |
| | | |
| | | UIView.animate(withDuration: 0.35) { |
| | | pickerView.backgroundColor = UIColor.black.withAlphaComponent(0.7) |
| | | pickerView.view_content.snp.updateConstraints { make in |
| | | make.bottom.equalToSuperview() |
| | | } |
| | | pickerView.layoutIfNeeded() |
| | | }completion: { _ in |
| | | Services.addressTree().subscribe(onNext: {data in |
| | | pickerView.items = data.data ?? [] |
| | | pickerView.picker.reloadAllComponents() |
| | | }).disposed(by: pickerView.disposeBag) |
| | | } |
| | | } |
| | | |
| | | @objc func closeAction(){ |
| | | UIView.animate(withDuration: 0.35) { |
| | | self.backgroundColor = UIColor.black.withAlphaComponent(0) |
| | | self.view_content.snp.updateConstraints { make in |
| | | make.bottom.equalToSuperview().offset(JQ_ScreenW * 0.3278) |
| | | } |
| | | self.layoutIfNeeded() |
| | | }completion: { _ in |
| | | self.removeFromSuperview() |
| | | } |
| | | } |
| | | |
| | | @objc func completeAction(){ |
| | | |
| | | let provinceIndex = picker.selectedRow(inComponent: 0) |
| | | let provinceModel = items[provinceIndex] |
| | | let cityModel = items[provinceIndex].children?[picker.selectedRow(inComponent: 1)] |
| | | let countryModel = items[provinceIndex].children?[picker.selectedRow(inComponent: 1)].children?[picker.selectedRow(inComponent: 2)] |
| | | clouse(provinceModel,cityModel,countryModel) |
| | | closeAction() |
| | | } |
| | | } |
| | | |
| | | extension CityAddressPickerView:UIPickerViewDelegate & UIPickerViewDataSource{ |
| | | func numberOfComponents(in pickerView: UIPickerView) -> Int { |
| | | if items.count > 0{ |
| | | return 3 |
| | | } |
| | | return 0 |
| | | |
| | | } |
| | | |
| | | func pickerView(_ pickerView: UIPickerView, rowHeightForComponent component: Int) -> CGFloat { |
| | | return 40 |
| | | } |
| | | |
| | | func pickerView(_ pickerView: UIPickerView, viewForRow row: Int, forComponent component: Int, reusing view: UIView?) -> UIView { |
| | | |
| | | var resultLabel:UILabel? |
| | | if let label = view as? UILabel{ |
| | | resultLabel = label |
| | | }else{ |
| | | resultLabel = UILabel() |
| | | resultLabel!.font = UIFont.systemFont(ofSize: 18, weight: .semibold) |
| | | resultLabel!.textColor = UIColor(hexStr: "#3C3C3C") |
| | | resultLabel!.textAlignment = .center |
| | | } |
| | | |
| | | if component == 0{ |
| | | resultLabel!.text = items[row].name |
| | | } |
| | | |
| | | if component == 1{ |
| | | let v = items[pickerView.selectedRow(inComponent: 0)] |
| | | resultLabel!.text = v.children?[row].name ?? "" |
| | | } |
| | | |
| | | if component == 2{ |
| | | let v = items[pickerView.selectedRow(inComponent: 0)] |
| | | let v1 = v.children?[pickerView.selectedRow(inComponent: 1)] |
| | | resultLabel!.text = v1?.children?[row].name ?? "" |
| | | } |
| | | |
| | | return resultLabel! |
| | | } |
| | | |
| | | func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int { |
| | | if component == 0 { |
| | | return items.count |
| | | } |
| | | |
| | | if component == 1{ |
| | | let index = pickerView.selectedRow(inComponent: 0) |
| | | return items[index].children?.count ?? 0 |
| | | } |
| | | |
| | | if component == 2{ |
| | | let indexI = pickerView.selectedRow(inComponent: 0) |
| | | let indexJ = pickerView.selectedRow(inComponent: 1) |
| | | return items[indexI].children?[indexJ].children?.count ?? 0 |
| | | } |
| | | |
| | | return 0 |
| | | } |
| | | |
| | | func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) { |
| | | if component == 0{ |
| | | pickerView.reloadComponent(1) |
| | | pickerView.reloadComponent(2) |
| | | } |
| | | |
| | | if component == 1{ |
| | | pickerView.reloadComponent(2) |
| | | } |
| | | } |
| | | } |
New file |
| | |
| | | // |
| | | // CommonBannerView.swift |
| | | // WanPai |
| | | // |
| | | // Created by 无故事王国 on 2023/6/30. |
| | | // |
| | | |
| | | import UIKit |
| | | import SDWebImage |
| | | struct CommonBannerModel { |
| | | var index = 0 //自定义索引 |
| | | var id:Int? //ID |
| | | var name:String? //名称 |
| | | var resource:String? //数据源:URL等 |
| | | var mediaType:CommonBannerView.MediaType? |
| | | } |
| | | |
| | | class CommonBannerView: UIView, UICollectionViewDelegate, UICollectionViewDataSource,UICollectionViewDelegateFlowLayout { |
| | | |
| | | enum MediaType { |
| | | case videoUrl,imageUrl,imageLocal,videoLocal |
| | | } |
| | | |
| | | private lazy var collectionView:UICollectionView = { |
| | | var layout = UICollectionViewFlowLayout() |
| | | layout.minimumLineSpacing = 0 |
| | | layout.minimumInteritemSpacing = 0 |
| | | layout.scrollDirection = .horizontal |
| | | layout.sectionInset = .zero |
| | | layout.headerReferenceSize = .zero |
| | | layout.footerReferenceSize = .zero |
| | | layout.itemSize = CGSize(width: self.width, height: self.height) |
| | | let collectionView = UICollectionView(frame:CGRect(x: 0, y: 0, width: self.width, height: self.height), collectionViewLayout: layout) |
| | | collectionView.delegate = self |
| | | collectionView.dataSource = self |
| | | collectionView.isPagingEnabled = true |
| | | collectionView.showsHorizontalScrollIndicator = false |
| | | collectionView.register(CommonBannerViewCell.self, forCellWithReuseIdentifier: "BannerView") |
| | | collectionView.decelerationRate = .normal |
| | | collectionView.contentInsetAdjustmentBehavior = .never |
| | | collectionView.backgroundColor = .white |
| | | collectionView.bounces = false |
| | | return collectionView |
| | | }() |
| | | |
| | | private lazy var pageControl:UIPageControl = { |
| | | let control = UIPageControl() |
| | | control.currentPageIndicatorTintColor = .white |
| | | control.pageIndicatorTintColor = .gray.withAlphaComponent(0.6) |
| | | return control |
| | | }() |
| | | |
| | | private var timer:Timer? |
| | | |
| | | private var items = [CommonBannerModel]() |
| | | private var selectClouse:((CommonBannerModel)->Void)? |
| | | private var autoRoll:Bool = true |
| | | private var currentPage:Int = 0 |
| | | private var timeInterval:Int = 5 |
| | | |
| | | override func awakeFromNib() { |
| | | super.awakeFromNib() |
| | | setUI() |
| | | } |
| | | |
| | | public func setItems(items:[CommonBannerModel],autoRoll:Bool = true,selectClouse:((CommonBannerModel)->Void)? = nil){ |
| | | |
| | | self.items = items |
| | | if items.count > 1{ |
| | | self.items.append(items.first!) |
| | | } |
| | | self.autoRoll = autoRoll |
| | | self.selectClouse = selectClouse |
| | | if items.count <= 1{self.autoRoll = false} |
| | | |
| | | setUI() |
| | | collectionView.reloadData() |
| | | |
| | | if self.autoRoll{ |
| | | DispatchQueue.main.asyncAfter(deadline: .now()+5) { |
| | | self.startTimer() |
| | | } |
| | | } |
| | | } |
| | | |
| | | private func setUI(){ |
| | | addSubview(collectionView) |
| | | collectionView.snp.makeConstraints { make in |
| | | make.edges.equalToSuperview() |
| | | } |
| | | |
| | | if items.count > 1{ |
| | | pageControl.numberOfPages = items.count - 1 |
| | | |
| | | addSubview(pageControl) |
| | | pageControl.snp.makeConstraints { make in |
| | | make.centerX.equalToSuperview() |
| | | make.bottom.equalToSuperview().offset(-10) |
| | | make.height.equalTo(8) |
| | | } |
| | | } |
| | | } |
| | | |
| | | private func startTimer(){ |
| | | timer = Timer(timeInterval: TimeInterval(timeInterval), repeats: true, block: {[weak self] t in |
| | | guard let weakSelf = self else { return } |
| | | |
| | | var page = weakSelf.collectionView.contentOffset.x / weakSelf.collectionView.width |
| | | weakSelf.currentPage = Int(page + 1) |
| | | |
| | | if weakSelf.currentPage >= weakSelf.pageControl.numberOfPages{ |
| | | weakSelf.currentPage = 0 |
| | | weakSelf.collectionView.setContentOffset(.zero, animated: false) |
| | | weakSelf.pageControl.currentPage = 0 |
| | | } |
| | | weakSelf.collectionView.setContentOffset(CGPoint(x: weakSelf.currentPage * Int(weakSelf.width), y: 0), animated: true) |
| | | }) |
| | | timer?.fire() |
| | | RunLoop.current.add(timer!, forMode: .common) |
| | | } |
| | | |
| | | func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { |
| | | return items.count |
| | | } |
| | | |
| | | func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) { |
| | | let item = items[indexPath.row] |
| | | selectClouse?(item) |
| | | } |
| | | |
| | | func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize { |
| | | return CGSize(width:collectionView.bounds.size.width,height:ceil(collectionView.bounds.size.height)) |
| | | } |
| | | |
| | | func scrollViewWillBeginDragging(_ scrollView: UIScrollView) { |
| | | print("--开始滑动") |
| | | timer?.fireDate = Date.distantFuture |
| | | } |
| | | |
| | | func scrollViewDidEndDragging(_ scrollView: UIScrollView, willDecelerate decelerate: Bool) { |
| | | let page = scrollView.contentOffset.x / scrollView.width |
| | | if page.int >= pageControl.numberOfPages{ |
| | | pageControl.currentPage = 0 |
| | | }else{ |
| | | pageControl.currentPage = page.int |
| | | } |
| | | print("--结束滑动") |
| | | timer?.fireDate = Date.init(timeIntervalSinceNow: 3.0) //3秒后开启 |
| | | } |
| | | |
| | | func scrollViewDidEndScrollingAnimation(_ scrollView: UIScrollView) { |
| | | let page = scrollView.contentOffset.x / scrollView.width |
| | | if page.int >= pageControl.numberOfPages{ |
| | | pageControl.currentPage = 0 |
| | | }else{ |
| | | pageControl.currentPage = page.int |
| | | } |
| | | } |
| | | |
| | | func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) { |
| | | let page = scrollView.contentOffset.x / scrollView.width |
| | | if page.int >= pageControl.numberOfPages{ |
| | | pageControl.currentPage = 0 |
| | | collectionView.setContentOffset(.zero, animated: false) |
| | | }else{ |
| | | pageControl.currentPage = page.int |
| | | } |
| | | } |
| | | |
| | | func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { |
| | | let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "BannerView", for: indexPath) as! CommonBannerViewCell |
| | | let item = items[indexPath.row] |
| | | |
| | | switch item.mediaType { |
| | | case .imageUrl: |
| | | if let i = item.resource{ |
| | | cell.imgView.sd_setImage(with: URL(string: i)) |
| | | } |
| | | case .imageLocal: |
| | | if let i = item.resource{ |
| | | cell.imgView.image = UIImage(named: i) |
| | | } |
| | | default:break |
| | | } |
| | | return cell |
| | | } |
| | | } |
| | | |
| | | class CommonBannerViewCell: UICollectionViewCell { |
| | | |
| | | lazy var imgView:UIImageView = { |
| | | let img = UIImageView() |
| | | img.contentMode = .scaleToFill |
| | | return img |
| | | }() |
| | | |
| | | override init(frame: CGRect) { |
| | | super.init(frame: frame) |
| | | contentView.addSubview(imgView) |
| | | imgView.snp.makeConstraints { make in |
| | | make.edges.equalToSuperview() |
| | | } |
| | | } |
| | | |
| | | required init?(coder aDecoder: NSCoder) { |
| | | fatalError("init(coder:) has not been implemented") |
| | | } |
| | | } |
| | |
| | | SVProgressHUD.setMaximumDismissTimeInterval(1.5) |
| | | SVProgressHUD.setDefaultMaskType(.custom) |
| | | |
| | | guard let tokenModel = LoginTokenModel.getToken(),!LoginTokenModel.isOverdue() else { |
| | | needLogin() |
| | | return |
| | | } |
| | | loginSuccess() |
| | | } |
| | | |
New file |
| | |
| | | // |
| | | // NetworkRequest.swift |
| | | // HandyJSON |
| | | // |
| | | // Created by Sweet on 2018/12/25. |
| | | // Copyright © 2018 Sweet. All rights reserved. |
| | | // |
| | | |
| | | import Foundation |
| | | import SwifterSwift |
| | | import Alamofire |
| | | import HandyJSON |
| | | import RxSwift |
| | | import SVProgressHUD |
| | | import JQTools |
| | | |
| | | // 假设这是服务端返回的统一定义的response格式 |
| | | struct BaseResponse<T :HandyJSON>: HandyJSON { |
| | | var sysTime: Int = 0 |
| | | var code: Int = -1 // 服务端返回码 |
| | | var data: T? = nil // 具体的data的格式和业务相关,故用泛型定义 |
| | | var msg: String = "" |
| | | } |
| | | |
| | | struct BaseData<T: HandyJSON>: HandyJSON { |
| | | var records = [T]() |
| | | } |
| | | |
| | | struct SimpleModel: HandyJSON { |
| | | |
| | | } |
| | | struct HtmlModel: HandyJSON { |
| | | var content = "" |
| | | var content1 = "" |
| | | var id = 0 |
| | | var type = 0 |
| | | } |
| | | |
| | | extension String: HandyJSON{ |
| | | |
| | | } |
| | | extension Array: HandyJSON{ |
| | | |
| | | } |
| | | extension Bool: HandyJSON{ |
| | | |
| | | } |
| | | |
| | | extension Int: HandyJSON{ |
| | | |
| | | } |
| | | |
| | | let SHAKEY = "" |
| | | |
| | | class ParamsAppender: NSObject { |
| | | var url: URL |
| | | var params:Dictionary = [String: Any]() |
| | | |
| | | private init(url: String){ |
| | | self.url = URL(string: url)! |
| | | } |
| | | |
| | | @discardableResult |
| | | func interface(url: String) -> ParamsAppender { |
| | | self.url.appendPathComponent(url) |
| | | return self |
| | | } |
| | | |
| | | @discardableResult |
| | | func append(key: String,value: Bool) -> ParamsAppender { |
| | | params += ["\(key)":"\(value)"] |
| | | return self |
| | | } |
| | | |
| | | @discardableResult |
| | | func append(key: String,value: String?) -> ParamsAppender { |
| | | if value != nil && value?.isEmpty == false { |
| | | params += ["\(key)":"\(value!)"] |
| | | } |
| | | return self |
| | | } |
| | | |
| | | @discardableResult |
| | | func append(key: String,value: Array<String>) -> ParamsAppender { |
| | | if value.isEmpty == false { |
| | | params += ["\(key)":value] |
| | | } |
| | | return self |
| | | } |
| | | |
| | | |
| | | @discardableResult |
| | | func append(key: String, value: Int?) -> ParamsAppender { |
| | | if value != nil{ |
| | | params += ["\(key)":value!] |
| | | } |
| | | return self |
| | | } |
| | | |
| | | @discardableResult |
| | | func append(key: String, value: Int64) -> ParamsAppender { |
| | | params += ["\(key)":value] |
| | | return self |
| | | } |
| | | |
| | | @discardableResult |
| | | func append(key: String, value: Double?) -> ParamsAppender { |
| | | if value != nil{ |
| | | params += ["\(key)":value!] |
| | | } |
| | | return self |
| | | } |
| | | |
| | | @discardableResult |
| | | func append(key: String,data: Data?) -> ParamsAppender { |
| | | if data != nil{ |
| | | params += ["\(key)": data!] |
| | | } |
| | | return self |
| | | } |
| | | |
| | | @discardableResult |
| | | func append(key: String,url: URL) -> ParamsAppender { |
| | | params += ["\(key)":"\(url)"] |
| | | return self |
| | | } |
| | | |
| | | @discardableResult |
| | | func append(dic: [String : Any]) -> ParamsAppender { |
| | | params += dic |
| | | return self |
| | | } |
| | | |
| | | /// 参数加密 |
| | | @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 |
| | | } |
| | | return self.params |
| | | } |
| | | |
| | | class func build(url: String) -> ParamsAppender { |
| | | return ParamsAppender(url: url) |
| | | } |
| | | |
| | | } |
| | | class NetworkRequest { |
| | | |
| | | static let sharedSessionManager: Alamofire.Session = { |
| | | let configuration = URLSessionConfiguration.default |
| | | configuration.timeoutIntervalForRequest = 10 |
| | | return Alamofire.Session(configuration: configuration) |
| | | }() |
| | | enum NetRequestError: Error { |
| | | case Other(Int,String) |
| | | case URLNotFound |
| | | case DownloadFailed |
| | | case InvaildSession |
| | | case ModelError(String) |
| | | case DataAnalysis(String) |
| | | } |
| | | |
| | | class func request<T: HandyJSON>(params: ParamsAppender, method: HTTPMethod, encoding: ParameterEncoding? = nil, progress: Bool = true,ignoreAlert:Bool = false) -> Observable<BaseResponse<T>>{ |
| | | |
| | | return Observable<BaseResponse<T>>.create{ ob in |
| | | guard NetworkReachabilityManager.init(host: All_Url)!.isReachable else { |
| | | alertError(msg: "当前网络不可用") |
| | | ob.onError(AFError.invalidURL(url: params.url)) |
| | | return Disposables.create{} |
| | | } |
| | | |
| | | if progress {showHUD()} |
| | | |
| | | var headers = HTTPHeaders() |
| | | |
| | | if let token = LoginTokenModel.getToken()?.access_token{ |
| | | headers.add(name: "Authorization", value: "Bearer" + " " + token) |
| | | LogInfo("USER_token:Bearer \(token)") |
| | | } |
| | | |
| | | if encoding is JSONEncoding { |
| | | headers.add(name: "Content-Type", value: "application/json;charset=UTF-8") |
| | | } |
| | | |
| | | var newEncoding: ParameterEncoding |
| | | if encoding != nil { |
| | | newEncoding = encoding! |
| | | } else { |
| | | newEncoding = method == .post ? URLEncoding.httpBody : URLEncoding.queryString |
| | | } |
| | | |
| | | sharedSessionManager.request(params.url.absoluteString, method: method, parameters:params.done(), encoding: newEncoding, headers:headers).validate().responseData{response in |
| | | LogInfo("请求地址:\(params.url)") |
| | | LogInfo("请求参数:\(params.params)") |
| | | hiddenHUD() |
| | | |
| | | guard response.error == nil else { |
| | | LogError("\(response.error!)") |
| | | |
| | | var errorString = "" |
| | | errorString.append("服务器故障:\(response.error!.localizedDescription)") |
| | | if let code = response.error?.responseCode{ |
| | | errorString.append("\n【错误码:\(code)】") |
| | | } |
| | | if !ignoreAlert{ |
| | | alert(msg: errorString) |
| | | } |
| | | ob.onError(response.error!) |
| | | return |
| | | } |
| | | if let data = response.data,let jsonString = String(data: data, encoding: String.Encoding.utf8){ |
| | | LogResponse(try! JSONSerialization.jsonObject(with: data)) |
| | | if let next = BaseResponse<T>.deserialize(from: jsonString){ |
| | | switch next.code{ |
| | | case 200:ob.onNext(next) |
| | | case 504: //登录设备最大限制 |
| | | let attribute = AttributedStringbuilder.build().add(string:next.msg, withFont: .systemFont(ofSize: 14, weight: .medium), withColor: .black.withAlphaComponent(0.6)).mutableAttributedString |
| | | // CommonAlertView.show(title: "提示", attribute: attribute, cancelStr: "关闭", completeStr: "关闭", isSingle: true, customBtnWidth: JQ_ScreenW - 170) { _ in |
| | | // |
| | | // } |
| | | case 503: //登录被冻结 |
| | | let attribute = AttributedStringbuilder.build().add(string:next.msg, withFont: .systemFont(ofSize: 14, weight: .medium), withColor: .black.withAlphaComponent(0.6)).mutableAttributedString |
| | | // CommonAlertView.show(title: "提示", attribute: attribute, cancelStr: "关闭", completeStr: "关闭", isSingle: true, customBtnWidth: JQ_ScreenW - 170) { _ in |
| | | // |
| | | // } |
| | | // case 501: |
| | | // CommonAlertView.show(title: "提示", content: next.msg,isSingle: true) { _ in |
| | | // |
| | | // } |
| | | // ob.onError(NetRequestError.InvaildSession) |
| | | case 401: |
| | | if !ignoreAlert{ |
| | | alertError(msg: "登录失效,请重新登录");ob.onError(NetRequestError.InvaildSession) |
| | | } |
| | | sceneDelegate?.needLogin() |
| | | default: |
| | | if !ignoreAlert{ |
| | | alertError(msg: "\(next.msg)") |
| | | } |
| | | ob.onError(NetRequestError.Other(next.code,next.msg)) |
| | | } |
| | | } |
| | | } |
| | | ob.onCompleted() |
| | | } |
| | | return Disposables.create{} |
| | | } |
| | | } |
| | | } |
| | | extension Dictionary { |
| | | mutating func append(dict: Dictionary) { |
| | | dict.forEach { (key, value) in |
| | | self.updateValue(value, forKey: key) |
| | | } |
| | | } |
| | | } |
| | | |
| | | |
| | | func createError(text:String,code:Int)->AFError{ |
| | | return AFError.createURLRequestFailed(error: NSError(domain: text, code: code)) |
| | | } |
New file |
| | |
| | | // |
| | | // Services.swift |
| | | // YixiuShop |
| | | // |
| | | // Created by Sweet on 2019/9/30. |
| | | // Copyright © 2019 jackLove. All rights reserved. |
| | | // |
| | | |
| | | import UIKit |
| | | import RxSwift |
| | | import Alamofire |
| | | import JQTools |
| | | |
| | | #if DEBUG |
| | | let All_Url = "http://192.168.110.237:9000" |
| | | #else |
| | | let All_Url = "http://192.168.110.237:9000" |
| | | #endif |
| | | |
| | | class Services: NSObject { |
| | | |
| | | } |
| | | |
| | | extension Services{ |
| | | class func weekList(quarter:Int)->Observable<BaseResponse<[ListenWeekModel]>>{ |
| | | let params = ParamsAppender.build(url: All_Url) |
| | | params.interface(url: "/study/base/study/weekList") |
| | | params.append(key: "quarter", value: quarter) |
| | | return NetworkRequest.request(params: params, method: .get, progress: false) |
| | | } |
| | | } |
| | | |
| | | // MARK: -- 登录部分 |
| | | extension Services{ |
| | | class func sendPhoneCode(phone:String)->Observable<BaseResponse<SimpleModel>>{ |
| | | let params = ParamsAppender.build(url: All_Url) |
| | | params.interface(url: "/study/base/user/sendPhoneCode") |
| | | params.append(key: "phone", value: phone) |
| | | return NetworkRequest.request(params: params, method: .get, progress: true) |
| | | } |
| | | |
| | | class func login(phone:String,code:String)->Observable<BaseResponse<LoginModel>>{ |
| | | let params = ParamsAppender.build(url: All_Url) |
| | | params.interface(url: "/study/base/user/studyLogin") |
| | | params.append(key: "phone", value: phone) |
| | | params.append(key: "phoneCode", value: code) |
| | | return NetworkRequest.request(params: params, method: .post,encoding: JSONEncoding.default, progress: true) |
| | | } |
| | | } |
| | | |
| | | // MARK: -- 首页 |
| | | extension Services{ |
| | | |
| | | } |
| | | |
| | | |
| | | // MARK: -- 商品 |
| | | extension Services{ |
| | | class func goodRecommend()->Observable<BaseResponse<[RecommendModel]>>{ |
| | | let params = ParamsAppender.build(url: All_Url) |
| | | params.interface(url: "/study/base/study/goodRecommend") |
| | | return NetworkRequest.request(params: params, method: .get, progress: false) |
| | | } |
| | | |
| | | class func goodsList(keywords:String,page:Int,pageSize:Int = 20,type:[String])->Observable<BaseResponse<BaseResponseList<MarketModel>>>{ |
| | | let params = ParamsAppender.build(url: All_Url) |
| | | params.interface(url: "/goods/base/goods/goodListStudy") |
| | | .append(key: "keywords", value: keywords) |
| | | .append(key: "pageNumber", value: page) |
| | | .append(key: "pageSize", value: pageSize) |
| | | .append(key: "type", value: type) |
| | | return NetworkRequest.request(params: params, method: .post,encoding: JSONEncoding.default, progress: false) |
| | | } |
| | | |
| | | class func getIntegral()->Observable<BaseResponse<Int>>{ |
| | | let params = ParamsAppender.build(url: All_Url) |
| | | params.interface(url: "/study/base/study/getIntegralStudy") |
| | | return NetworkRequest.request(params: params, method: .get, progress: false) |
| | | } |
| | | |
| | | class func goodTypeStudy()->Observable<BaseResponse<[MarketTypeModel]>>{ |
| | | let params = ParamsAppender.build(url: All_Url) |
| | | params.interface(url: "/goods/base/goods/goodTypeStudy") |
| | | return NetworkRequest.request(params: params, method: .get, progress: false) |
| | | } |
| | | |
| | | class func goodsDetail(goodsId:Int)->Observable<BaseResponse<MarketDetailModel>>{ |
| | | let params = ParamsAppender.build(url: All_Url) |
| | | params.interface(url: "/goods/base/goods/goodDetail") |
| | | .append(key: "goodId", value: goodsId) |
| | | return NetworkRequest.request(params: params, method: .get, progress: true) |
| | | } |
| | | |
| | | class func addressList()->Observable<BaseResponse<[AddressModel]>>{ |
| | | let params = ParamsAppender.build(url: All_Url) |
| | | params.interface(url: "/goods/base/goods/shopAddress") |
| | | return NetworkRequest.request(params: params, method: .get, progress: false) |
| | | } |
| | | |
| | | class func deleteAddress(id:Int)->Observable<BaseResponse<SimpleModel>>{ |
| | | let params = ParamsAppender.build(url: All_Url) |
| | | params.interface(url: "/goods/base/goods/addressDelete") |
| | | .append(key: "id", value: id) |
| | | return NetworkRequest.request(params: params, method: .get, progress: true) |
| | | } |
| | | |
| | | class func redeemNow(goodId:Int)->Observable<BaseResponse<MarketDetailModel>>{ |
| | | let params = ParamsAppender.build(url: All_Url) |
| | | params.interface(url: "/goods/base/goods/redeemNow") |
| | | .append(key: "goodId", value: goodId) |
| | | return NetworkRequest.request(params: params, method: .get, progress: true) |
| | | } |
| | | |
| | | class func addressTree()->Observable<BaseResponse<[AddressTreeModel]>>{ |
| | | let params = ParamsAppender.build(url: All_Url) |
| | | params.interface(url: "/goods/base/goods/addressTree") |
| | | return NetworkRequest.request(params: params, method: .get, progress: true) |
| | | } |
| | | |
| | | class func addressSaveOrUpdate(id:Int?,province:AddressTreeModel?,city:AddressTreeModel?,country:AddressTreeModel?,userName:String?,userPhone:String?,isDefault:Bool,detailAddress:String)->Observable<BaseResponse<SimpleModel>>{ |
| | | let params = ParamsAppender.build(url: All_Url) |
| | | params.interface(url: "/goods/base/goods/addressSaveOrUpdate") |
| | | .append(key: "id", value: id) |
| | | .append(key: "address", value: detailAddress) |
| | | .append(key: "city", value: city?.name) |
| | | .append(key: "cityCode", value: city?.code) |
| | | .append(key: "province", value: province?.name) |
| | | .append(key: "provinceCode", value: province?.code) |
| | | .append(key: "recipient", value: userName) |
| | | .append(key: "recipientPhone", value: userPhone) |
| | | .append(key: "isDefault", value: (isDefault == true) ? 1:0) |
| | | return NetworkRequest.request(params: params, method: .post,encoding: JSONEncoding.default, progress: true) |
| | | } |
| | | |
| | | class func setDefaultStudy(id:Int)->Observable<BaseResponse<SimpleModel>>{ |
| | | let params = ParamsAppender.build(url: All_Url) |
| | | params.interface(url: "/goods/base/goods/setDefaultStudy") |
| | | .append(key: "id", value: id) |
| | | return NetworkRequest.request(params: params, method: .get, progress: true) |
| | | } |
| | | |
| | | class func goodsExchangeStudy(goodsId:Int,number:Int,orderNumber:String,recipientId:Int,remark:String)->Observable<BaseResponse<SimpleModel>>{ |
| | | let params = ParamsAppender.build(url: All_Url) |
| | | params.interface(url: "/goods/base/goods/goodExchangeStudy") |
| | | .append(key: "goodId", value: goodsId) |
| | | .append(key: "number", value: number) |
| | | .append(key: "orderNumber", value: orderNumber) |
| | | .append(key: "recipientId", value: recipientId) |
| | | .append(key: "remark", value: remark) |
| | | return NetworkRequest.request(params: params, method: .post,encoding: JSONEncoding.default, progress: true) |
| | | } |
| | | |
| | | class func userInfo()->Observable<BaseResponse<UserInfoModel>>{ |
| | | let params = ParamsAppender.build(url: All_Url) |
| | | params.interface(url: "/study/base/user/userInfo") |
| | | return NetworkRequest.request(params: params, method: .get, progress: false) |
| | | } |
| | | |
| | | class func integralDetail(pageNum:Int,pageSize:Int = 20,time:String?)->Observable<BaseResponse<BaseResponseList<IntegralModel>>>{ |
| | | let params = ParamsAppender.build(url: All_Url) |
| | | params.interface(url: "/study/base/study/integralDetail") |
| | | .append(key: "pageNum", value: pageNum) |
| | | .append(key: "pageSize", value: pageSize) |
| | | .append(key: "time", value: time) |
| | | return NetworkRequest.request(params: params, method: .get, progress: false) |
| | | } |
| | | |
| | | class func exchangeRecord()->Observable<BaseResponse<[ExchangeRecordModel]>>{ |
| | | let params = ParamsAppender.build(url: All_Url) |
| | | params.interface(url: "/goods/base/goods/exchangeRecord") |
| | | return NetworkRequest.request(params: params, method: .get, progress: false) |
| | | } |
| | | |
| | | class func studyGamesRecord()->Observable<BaseResponse<StudyGamesModel>>{ |
| | | let params = ParamsAppender.build(url: All_Url) |
| | | params.interface(url: "/study/base/study/record") |
| | | return NetworkRequest.request(params: params, method: .get, progress: true) |
| | | } |
| | | |
| | | class func logoutStudy()->Observable<BaseResponse<SimpleModel>>{ |
| | | let params = ParamsAppender.build(url: All_Url) |
| | | params.interface(url: "/study/base/user/logoutStudy") |
| | | return NetworkRequest.request(params: params, method: .post,encoding: JSONEncoding.default, progress: true) |
| | | } |
| | | |
| | | } |
| | | |
| | | extension Services{ |
| | | class func getAgreement(type:AgreementType)->Observable<BaseResponse<String>>{ |
| | | let params = ParamsAppender.build(url: All_Url) |
| | | params.interface(url: "/study/base/user/getProtocol") |
| | | params.append(key: "type", value: type.rawValue) |
| | | return NetworkRequest.request(params: params, method: .post, progress: true) |
| | | } |
| | | } |
| | | |
| | | |
| | | extension Services{ |
| | | static func startNetworkMonitor(){ |
| | | let manager = NetworkReachabilityManager(host: All_Url) |
| | | manager?.startListening(onUpdatePerforming: { status in |
| | | switch status { |
| | | case .notReachable:alertError(msg: "当前网络不可用") |
| | | case .reachable(let type): |
| | | switch type{ |
| | | case .ethernetOrWiFi:alert(msg: "当前为Wi-Fi网络") |
| | | case .cellular:alert(msg: "当前为移动网络") |
| | | } |
| | | default:break |
| | | } |
| | | }) |
| | | } |
| | | } |
New file |
| | |
| | | // |
| | | // RefreshModel.swift |
| | | // WanPai |
| | | // |
| | | // Created by 无故事王国 on 2023/7/11. |
| | | // |
| | | |
| | | import UIKit |
| | | import MJRefresh |
| | | import RxSwift |
| | | import HandyJSON |
| | | import RxRelay |
| | | |
| | | |
| | | enum RefreshState { |
| | | case refreshing |
| | | case completedRefresh |
| | | case moreLoading |
| | | case completedLoad |
| | | case completedLoadWithNoMoreData |
| | | } |
| | | |
| | | struct BaseResponseList<T :HandyJSON>: HandyJSON { |
| | | var records: [T] = [] |
| | | var current:Int = 0 |
| | | var hasNextPage:Bool = false |
| | | var hasPrevPage:Bool = false |
| | | var pages:Int = 0 |
| | | var size:Int = 0 |
| | | var startIndex:Int = 0 |
| | | var total:Int = 0 |
| | | } |
| | | |
| | | protocol RefreshModelProctol { |
| | | associatedtype T:HandyJSON |
| | | func api()->(Observable<BaseResponse<[T]>>)? |
| | | } |
| | | |
| | | protocol RefreshModelInnerProctol { |
| | | associatedtype T:HandyJSON |
| | | func api()->(Observable<BaseResponse<BaseResponseList<T>>>)? |
| | | } |
| | | |
| | | |
| | | class RefreshModel<T:HandyJSON>:RefreshModelProctol{ |
| | | func api() -> (RxSwift.Observable<BaseResponse<[T]>>)? {return nil} |
| | | let disposeBag = DisposeBag() |
| | | enum RefreshType {case refresh,load} |
| | | |
| | | private var handle:UIScrollView! |
| | | |
| | | lazy var refreshSubject = PublishSubject<RefreshState>() |
| | | var page:Int = 1 |
| | | var pageSize:Int = 20 |
| | | private var needRefreshData:Bool = true |
| | | lazy var dataSource = BehaviorRelay<[T]>(value: []) |
| | | |
| | | func resetPage(){ |
| | | page = 1 |
| | | } |
| | | |
| | | func configure(_ scrollView:UITableView,needMore:Bool = true){ |
| | | scrollView.mj_header = CustomRefreshHeaer.refreshing(with: refreshData()) |
| | | if needMore{ |
| | | scrollView.mj_footer = CustomRefreshFooter.refreshing(with: loadMoreData()) |
| | | } |
| | | refreshSubject.bind(to: scrollView.rx.handlestatus()).disposed(by: disposeBag) |
| | | handle = scrollView |
| | | } |
| | | |
| | | func configure(_ scrollView:UICollectionView,needMore:Bool = true,needRefreshData:Bool = true){ |
| | | self.needRefreshData = needRefreshData |
| | | scrollView.mj_header = CustomRefreshHeaer.refreshing(with: refreshData()) |
| | | if needMore{ |
| | | scrollView.mj_footer = CustomRefreshFooter.refreshing(with: loadMoreData()) |
| | | } |
| | | refreshSubject.bind(to: scrollView.rx.handlestatus()).disposed(by: disposeBag) |
| | | handle = scrollView |
| | | } |
| | | |
| | | func beginRefresh(){ |
| | | guard handle != nil else {return} |
| | | api()?.subscribe(onNext: { data in |
| | | if let datas = data.data{ |
| | | self.dataSource.accept(datas) |
| | | self.refreshSubject.onNext(.completedRefresh) |
| | | } |
| | | }).disposed(by: disposeBag) |
| | | } |
| | | |
| | | func refreshData() ->(()->Void) { |
| | | return {self.request(status: .refresh)} |
| | | } |
| | | |
| | | func loadMoreData() ->(()->Void) { |
| | | return {self.request(status: .load)} |
| | | } |
| | | |
| | | func request(status:RefreshType){ |
| | | switch status { |
| | | case .refresh: |
| | | self.page = 1 |
| | | self.refreshSubject.onNext(.refreshing) |
| | | case .load: |
| | | self.page += 1 |
| | | self.refreshSubject.onNext(.moreLoading) |
| | | } |
| | | |
| | | api()?.subscribe(onNext: { data in |
| | | if let datas = data.data{ |
| | | switch status{ |
| | | case .refresh: |
| | | self.dataSource.accept(datas) |
| | | self.refreshSubject.onNext(.completedRefresh) |
| | | case .load: |
| | | self.dataSource.accept(self.dataSource.value + datas) |
| | | if datas.count == 0{ |
| | | self.refreshSubject.onNext(.completedLoadWithNoMoreData) |
| | | }else{ |
| | | self.refreshSubject.onNext(.completedLoad) |
| | | } |
| | | } |
| | | }else{ |
| | | self.refreshSubject.onNext(.completedLoadWithNoMoreData) |
| | | } |
| | | }, onError: { error in |
| | | self.refreshSubject.onNext(.completedLoad) |
| | | |
| | | }).disposed(by: disposeBag) |
| | | } |
| | | } |
| | | |
| | | |
| | | class RefreshInnerModel<T:HandyJSON>:RefreshModelInnerProctol{ |
| | | func api() -> (RxSwift.Observable<BaseResponse<BaseResponseList<T>>>)? { |
| | | return nil |
| | | } |
| | | |
| | | let disposeBag = DisposeBag() |
| | | enum RefreshType {case refresh,load} |
| | | |
| | | private var handle:UIScrollView! |
| | | |
| | | lazy var refreshSubject = PublishSubject<RefreshState>() |
| | | var page:Int = 0 |
| | | var pageSize:Int = 20 |
| | | private var needRefreshData:Bool = true |
| | | lazy var dataSource = BehaviorRelay<BaseResponseList<T>?>(value: nil) |
| | | |
| | | func configure(_ scrollView:UITableView,needMore:Bool = true){ |
| | | scrollView.mj_header = CustomRefreshHeaer.refreshing(with: refreshData()) |
| | | if needMore{ |
| | | scrollView.mj_footer = CustomRefreshFooter.refreshing(with: loadMoreData()) |
| | | } |
| | | refreshSubject.bind(to: scrollView.rx.handlestatus()).disposed(by: disposeBag) |
| | | handle = scrollView |
| | | } |
| | | |
| | | func configure(_ scrollView:UICollectionView,needMore:Bool = true,needRefreshData:Bool = true){ |
| | | self.needRefreshData = needRefreshData |
| | | scrollView.mj_header = CustomRefreshHeaer.refreshing(with: refreshData()) |
| | | if needMore{ |
| | | scrollView.mj_footer = CustomRefreshFooter.refreshing(with: loadMoreData()) |
| | | } |
| | | refreshSubject.bind(to: scrollView.rx.handlestatus()).disposed(by: disposeBag) |
| | | handle = scrollView |
| | | } |
| | | func resetPage(){ |
| | | page = 1 |
| | | } |
| | | |
| | | func beginRefresh(){ |
| | | handle.mj_header?.beginRefreshing() |
| | | } |
| | | |
| | | func refreshData() ->(()->Void) { |
| | | return {self.request(status: .refresh)} |
| | | } |
| | | |
| | | func loadMoreData() ->(()->Void) { |
| | | return {self.request(status: .load)} |
| | | } |
| | | |
| | | func request(status:RefreshType){ |
| | | switch status { |
| | | case .refresh: |
| | | self.page = 1 |
| | | self.refreshSubject.onNext(.refreshing) |
| | | case .load: |
| | | self.page += 1 |
| | | self.refreshSubject.onNext(.moreLoading) |
| | | } |
| | | |
| | | api()?.subscribe(onNext: { data in |
| | | switch status{ |
| | | case .refresh: |
| | | self.dataSource.accept(data.data) |
| | | self.refreshSubject.onNext(.completedRefresh) |
| | | case .load: |
| | | var new = self.dataSource.value?.records ?? [] |
| | | new.append(contentsOf: data.data?.records ?? []) |
| | | var model = self.dataSource.value |
| | | model!.records = new |
| | | self.dataSource.accept(model) |
| | | if data.data?.records.count == 0{ |
| | | self.refreshSubject.onNext(.completedLoadWithNoMoreData) |
| | | }else{ |
| | | self.refreshSubject.onNext(.completedLoad) |
| | | } |
| | | } |
| | | }, onError: { error in |
| | | self.refreshSubject.onNext(.completedLoad) |
| | | |
| | | }).disposed(by: disposeBag) |
| | | } |
| | | |
| | | |
| | | } |
| | | |
| | | |
| | | class CustomRefreshHeaer:MJRefreshNormalHeader{ |
| | | static func refreshing(with refreshingBlock: @escaping MJRefreshComponentAction) -> MJRefreshNormalHeader? { |
| | | let refreshHeader = MJRefreshNormalHeader(refreshingBlock: refreshingBlock) |
| | | return refreshHeader |
| | | } |
| | | } |
| | | |
| | | class CustomRefreshFooter:MJRefreshAutoNormalFooter{ |
| | | static func refreshing(with refreshingBlock: @escaping MJRefreshComponentAction) -> MJRefreshAutoNormalFooter? { |
| | | let refrehFooter = MJRefreshAutoNormalFooter(refreshingBlock: refreshingBlock) |
| | | refrehFooter.isRefreshingTitleHidden = true |
| | | refrehFooter.stateLabel?.isHidden = true |
| | | return refrehFooter |
| | | } |
| | | } |
| | | |
| | | extension Reactive where Base : UITableView { |
| | | |
| | | func handlestatus() -> Binder<RefreshState> { |
| | | return Binder(self.base) { (tableView, status) in |
| | | switch status { |
| | | case .moreLoading: |
| | | self.base.mj_footer?.beginRefreshing() |
| | | case .refreshing: |
| | | self.base.reloadData() |
| | | self.base.mj_footer?.resetNoMoreData() |
| | | self.base.mj_header?.beginRefreshing() |
| | | |
| | | case .completedLoadWithNoMoreData: |
| | | DispatchQueue.main.async { |
| | | self.base.reloadData() |
| | | } |
| | | (self.base.mj_footer as? MJRefreshAutoNormalFooter)?.stateLabel?.isHidden = false |
| | | self.base.mj_footer?.endRefreshingWithNoMoreData() |
| | | self.base.mj_header?.endRefreshing() |
| | | case .completedLoad: |
| | | DispatchQueue.main.async { |
| | | self.base.reloadData() |
| | | } |
| | | self.base.mj_footer?.endRefreshing() |
| | | self.base.mj_header?.endRefreshing() |
| | | default: |
| | | DispatchQueue.main.async { |
| | | self.base.reloadData() |
| | | } |
| | | self.base.mj_header?.endRefreshing() |
| | | self.base.mj_footer?.endRefreshing() |
| | | } |
| | | } |
| | | } |
| | | } |
| | | |
| | | extension Reactive where Base : UICollectionView { |
| | | |
| | | func handlestatus() -> Binder<RefreshState> { |
| | | return Binder(self.base) { (tableView, status) in |
| | | switch status { |
| | | case .moreLoading: |
| | | self.base.mj_footer?.beginRefreshing() |
| | | case .refreshing: |
| | | self.base.reloadData() |
| | | self.base.mj_footer?.resetNoMoreData() |
| | | self.base.mj_header?.endRefreshing() |
| | | |
| | | case .completedLoadWithNoMoreData: |
| | | DispatchQueue.main.async { |
| | | self.base.reloadData() |
| | | } |
| | | self.base.mj_footer?.endRefreshingWithNoMoreData() |
| | | case .completedLoad: |
| | | DispatchQueue.main.async { |
| | | self.base.reloadData() |
| | | } |
| | | self.base.mj_footer?.endRefreshing() |
| | | default: |
| | | DispatchQueue.main.async { |
| | | self.base.reloadData() |
| | | } |
| | | self.base.mj_header?.endRefreshing() |
| | | self.base.mj_footer?.endRefreshing() |
| | | } |
| | | } |
| | | } |
| | | } |
| | | |
New file |
| | |
| | | // |
| | | // UserViewModel.swift |
| | | // DolphinEnglishLearnStudent |
| | | // |
| | | // Created by 无故事王国 on 2024/5/30. |
| | | // |
| | | |
| | | import Foundation |
| | | import UserDefaultsStore |
| | | import HandyJSON |
| | | |
| | | struct UserInfoModel:HandyJSON,Identifiable,Codable{ |
| | | static let idKey = \UserInfoModel.id |
| | | var id: Int = 0 |
| | | var account: String = "" |
| | | var birthday: String = "" |
| | | var createBy: String = "" |
| | | var createTime: String = "" |
| | | var disabled: Bool = false |
| | | var gender: Int = 0 |
| | | var headImg: String = "" |
| | | var insertTime: String = "" |
| | | var integral: Int = 0 |
| | | var isVip: Int = 0 |
| | | var name: String = "" |
| | | var openId: String = "" |
| | | var password: String = "" |
| | | var phone: String = "" |
| | | var state: Int = 0 |
| | | var updateBy: String = "" |
| | | var updateTime: String = "" |
| | | var vipEndTime: String = "" |
| | | var vipPayTime: String = "" |
| | | |
| | | } |
| | | |
| | | class UserViewModel{ |
| | | private static let userInfo = UserDefaultsStore<UserInfoModel>(uniqueIdentifier: "UserInfoModel")! |
| | | |
| | | static func saveUserInfo(_ model:UserInfoModel){ |
| | | do{ |
| | | try UserViewModel.userInfo.save(model) |
| | | }catch{ |
| | | |
| | | } |
| | | } |
| | | |
| | | static func getUserInfo()->UserInfoModel?{ |
| | | return UserViewModel.userInfo.allObjects().first |
| | | } |
| | | |
| | | static func clearUserInfo(){ |
| | | UserViewModel.userInfo.deleteAll() |
| | | } |
| | | } |
| | |
| | | # pod 'Alamofire' # 网络请求框架 |
| | | pod 'SVProgressHUD' # 提示框组件 |
| | | pod 'CryptoSwift' # 常用加密算法 |
| | | pod 'Alamofire' # 网络请求框架 |
| | | |
| | | end |