younger_times
2023-07-10 31b6be2dfcc5a7e9300c90b2216dbd579153c3b0
新增
44个文件已修改
6 文件已重命名
25个文件已添加
2452 ■■■■ 已修改文件
Podfile 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
WanPai.xcodeproj/project.pbxproj 80 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
WanPai/AppDelegate.swift 46 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
WanPai/Assets.xcassets/AppIcon.appiconset/Contents.json 71 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
WanPai/Assets.xcassets/AppIcon.appiconset/icon-40@2x.png 补丁 | 查看 | 原始文档 | blame | 历史
WanPai/Assets.xcassets/AppIcon.appiconset/icon-40@3x.png 补丁 | 查看 | 原始文档 | blame | 历史
WanPai/Assets.xcassets/AppIcon.appiconset/icon-60@2x.png 补丁 | 查看 | 原始文档 | blame | 历史
WanPai/Assets.xcassets/AppIcon.appiconset/icon-60@3x.png 补丁 | 查看 | 原始文档 | blame | 历史
WanPai/Assets.xcassets/AppIcon.appiconset/icon-small.png 补丁 | 查看 | 原始文档 | blame | 历史
WanPai/Assets.xcassets/AppIcon.appiconset/icon-small@2x.png 补丁 | 查看 | 原始文档 | blame | 历史
WanPai/Assets.xcassets/AppIcon.appiconset/icon-small@3x.png 补丁 | 查看 | 原始文档 | blame | 历史
WanPai/Assets.xcassets/AppIcon.appiconset/icon.png 补丁 | 查看 | 原始文档 | blame | 历史
WanPai/Assets.xcassets/AppIcon.appiconset/icon@2x.png 补丁 | 查看 | 原始文档 | blame | 历史
WanPai/Assets.xcassets/AppIcon.appiconset/ios-marketing.png 补丁 | 查看 | 原始文档 | blame | 历史
WanPai/Assets.xcassets/AppIcon.appiconset/notification-icon@2x.png 补丁 | 查看 | 原始文档 | blame | 历史
WanPai/Assets.xcassets/AppIcon.appiconset/notification-icon@3x.png 补丁 | 查看 | 原始文档 | blame | 历史
WanPai/Assets.xcassets/Icons/icon_asc.imageset/Contents.json 补丁 | 查看 | 原始文档 | blame | 历史
WanPai/Assets.xcassets/Icons/icon_asc.imageset/icon_aes@2x.png 补丁 | 查看 | 原始文档 | blame | 历史
WanPai/Assets.xcassets/Icons/icon_asc.imageset/icon_aes@3x.png 补丁 | 查看 | 原始文档 | blame | 历史
WanPai/Assets.xcassets/Icons/icon_desc.imageset/Contents.json 补丁 | 查看 | 原始文档 | blame | 历史
WanPai/Assets.xcassets/Icons/icon_desc.imageset/icon_des@2x.png 补丁 | 查看 | 原始文档 | blame | 历史
WanPai/Assets.xcassets/Icons/icon_desc.imageset/icon_des@3x.png 补丁 | 查看 | 原始文档 | blame | 历史
WanPai/Assets.xcassets/Icons/icon_empty.imageset/Contents.json 22 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
WanPai/Assets.xcassets/Icons/icon_empty.imageset/icon_empty@2x.png 补丁 | 查看 | 原始文档 | blame | 历史
WanPai/Assets.xcassets/Icons/icon_empty.imageset/icon_empty@3x.png 补丁 | 查看 | 原始文档 | blame | 历史
WanPai/Assets.xcassets/Icons/icon_login_pwd.imageset/Contents.json 22 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
WanPai/Assets.xcassets/Icons/icon_login_pwd.imageset/icon_login_pwd@2x.png 补丁 | 查看 | 原始文档 | blame | 历史
WanPai/Assets.xcassets/Icons/icon_login_pwd.imageset/icon_login_pwd@3x.png 补丁 | 查看 | 原始文档 | blame | 历史
WanPai/Base.lproj/LaunchScreen.storyboard 28 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
WanPai/Base/BaseVC.swift 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
WanPai/Category/FinanceTrafer.swift 30 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
WanPai/Common/View/AgreentView.swift 20 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
WanPai/Common/View/AgreentView.xib 7 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
WanPai/Common/View/BaseTableView.swift 50 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
WanPai/Common/View/CommonBannerView.swift 378 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
WanPai/Config/Def.swift 20 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
WanPai/Config/Enums.swift 128 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
WanPai/Info.plist 16 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
WanPai/Model/CommonModels.swift 57 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
WanPai/Network/NetworkRequest.swift 375 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
WanPai/Network/Services.swift 164 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
WanPai/Root/Activity/VC/ActivityListVC.swift 3 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
WanPai/Root/Course/TCell/CourseTCell.swift 34 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
WanPai/Root/Course/TCell/CourseTCell.xib 46 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
WanPai/Root/Course/VC/CourseDetailVC.swift 84 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
WanPai/Root/Course/VC/CourseDetailVC.xib 33 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
WanPai/Root/Course/VC/CourseExerciseSubListVC.swift 3 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
WanPai/Root/Course/VC/CourseListVC.swift 147 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
WanPai/Root/Course/VC/CourseListVC.xib 16 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
WanPai/Root/Course/VC/CourseVideoDetailVC.swift 23 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
WanPai/Root/Course/VC/CourseVideoDetailVC.xib 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
WanPai/Root/Course/VC/StudentCourseDetailVC.swift 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
WanPai/Root/Course/View/CourseSubTypeView.swift 32 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
WanPai/Root/Home/CCell/HomeCCell.swift 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
WanPai/Root/Home/CCell/HomeCCell.xib 6 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
WanPai/Root/Home/Model/HomeModel.swift 35 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
WanPai/Root/Home/VC/HomeVC.swift 124 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
WanPai/Root/Home/VC/HomeVC.xib 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
WanPai/Root/Home/VC/JoinMemberIntroduceVC.swift 25 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
WanPai/Root/Home/VC/JoinMemberIntroduceVC.xib 13 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
WanPai/Root/Login/VC/LoginRegOrForgotVC.swift 76 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
WanPai/Root/Login/VC/LoginRegOrForgotVC.xib 23 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
WanPai/Root/Login/VC/LoginVC.swift 72 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
WanPai/Root/Login/VC/LoginVC.xib 24 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
WanPai/Root/Other/TCell/Common_1_TCell.swift 9 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
WanPai/Root/Other/TCell/Common_1_TCell.xib 8 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
WanPai/Root/Search/VC/SearchStoreDetailVC.swift 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
WanPai/Root/Search/VC/SearchStoreListVC.swift 3 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
WanPai/Root/Welfare/VC/WelfareBillListVC.swift 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
WanPai/Root/Welfare/VC/WelfareCouponsListVC.swift 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
WanPai/Root/Welfare/VC/WelfareExchangeRecordListVC.swift 3 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
WanPai/Root/Welfare/View/CoinStoreHeadView.swift 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
WanPai/Root/Yard/VC/YardListVC.swift 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
WanPai/SceneDelegate.swift 34 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
WanPai/ViewModel/UserModel.swift 26 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Podfile
@@ -11,6 +11,9 @@
  pod 'FFPage'
  pod 'SPPageMenu'
  pod 'FSCalendar'
  pod 'Alamofire'
  pod 'Lantern'
  pod 'SVProgressHUD'
  post_install do |installer|
    installer.pods_project.targets.each do |target|
WanPai.xcodeproj/project.pbxproj
@@ -47,6 +47,8 @@
        133A618D2A4E7AF90066C4E6 /* CustomerContentTCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = 133A618B2A4E7AF90066C4E6 /* CustomerContentTCell.xib */; };
        13489E0A2A4C41A400155744 /* ProfileVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = 13489E082A4C41A400155744 /* ProfileVC.swift */; };
        13489E0B2A4C41A400155744 /* ProfileVC.xib in Resources */ = {isa = PBXBuildFile; fileRef = 13489E092A4C41A400155744 /* ProfileVC.xib */; };
        1353D5752A56CA0A00539FCA /* Services.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1353D5732A56CA0A00539FCA /* Services.swift */; };
        1353D5762A56CA0A00539FCA /* NetworkRequest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1353D5742A56CA0A00539FCA /* NetworkRequest.swift */; };
        1355ABFA2A4BE9FF002B25E4 /* WelfareCouponsSubListVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1355ABF92A4BE9FF002B25E4 /* WelfareCouponsSubListVC.swift */; };
        1355ABFD2A4C15C7002B25E4 /* RechargeRecordVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1355ABFB2A4C15C7002B25E4 /* RechargeRecordVC.swift */; };
        1355ABFE2A4C15C7002B25E4 /* RechargeRecordVC.xib in Resources */ = {isa = PBXBuildFile; fileRef = 1355ABFC2A4C15C7002B25E4 /* RechargeRecordVC.xib */; };
@@ -56,6 +58,10 @@
        136FD9AE2A4C2F0500933B7C /* RechargeItemCCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = 136FD9AC2A4C2F0500933B7C /* RechargeItemCCell.xib */; };
        136FD9B12A4C354000933B7C /* WelfareRedeemGoodsDetailVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = 136FD9AF2A4C354000933B7C /* WelfareRedeemGoodsDetailVC.swift */; };
        136FD9B22A4C354000933B7C /* WelfareRedeemGoodsDetailVC.xib in Resources */ = {isa = PBXBuildFile; fileRef = 136FD9B02A4C354000933B7C /* WelfareRedeemGoodsDetailVC.xib */; };
        137546402A57F545001FA77A /* UserModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1375463F2A57F545001FA77A /* UserModel.swift */; };
        137546432A57F56F001FA77A /* CommonModels.swift in Sources */ = {isa = PBXBuildFile; fileRef = 137546422A57F56F001FA77A /* CommonModels.swift */; };
        137546452A58038B001FA77A /* BaseTableView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 137546442A58038B001FA77A /* BaseTableView.swift */; };
        1375464B2A581716001FA77A /* HomeModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1375464A2A581716001FA77A /* HomeModel.swift */; };
        1376A6952A4A765700D4C851 /* StudentInfo_3_TCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1376A6932A4A765700D4C851 /* StudentInfo_3_TCell.swift */; };
        1376A6962A4A765700D4C851 /* StudentInfo_3_TCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = 1376A6942A4A765700D4C851 /* StudentInfo_3_TCell.xib */; };
        1376A6992A4A7B7B00D4C851 /* StudentCourseDetailVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1376A6972A4A7B7A00D4C851 /* StudentCourseDetailVC.swift */; };
@@ -148,6 +154,7 @@
        13D7D6242A4EBBCF000136BD /* SearchStoreTCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = 13D7D6222A4EBBCF000136BD /* SearchStoreTCell.xib */; };
        13EC6DDC2A493D23009FC09A /* WelfareCoinCCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 13EC6DDA2A493D23009FC09A /* WelfareCoinCCell.swift */; };
        13EC6DDD2A493D23009FC09A /* WelfareCoinCCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = 13EC6DDB2A493D23009FC09A /* WelfareCoinCCell.xib */; };
        13FB93B92A5C028D009F558A /* FinanceTrafer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 13FB93B82A5C028D009F558A /* FinanceTrafer.swift */; };
        13FBB8D62A4ED96C00FF70DB /* SearchStoreDetailFeedbackVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = 13FBB8D42A4ED96C00FF70DB /* SearchStoreDetailFeedbackVC.swift */; };
        13FBB8D72A4ED96C00FF70DB /* SearchStoreDetailFeedbackVC.xib in Resources */ = {isa = PBXBuildFile; fileRef = 13FBB8D52A4ED96C00FF70DB /* SearchStoreDetailFeedbackVC.xib */; };
        13FBD7812A4AD62100037156 /* StudentMentalListVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = 13FBD7802A4AD62100037156 /* StudentMentalListVC.swift */; };
@@ -285,6 +292,8 @@
        133A618B2A4E7AF90066C4E6 /* CustomerContentTCell.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = CustomerContentTCell.xib; sourceTree = "<group>"; };
        13489E082A4C41A400155744 /* ProfileVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProfileVC.swift; sourceTree = "<group>"; };
        13489E092A4C41A400155744 /* ProfileVC.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = ProfileVC.xib; sourceTree = "<group>"; };
        1353D5732A56CA0A00539FCA /* Services.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Services.swift; sourceTree = "<group>"; };
        1353D5742A56CA0A00539FCA /* NetworkRequest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NetworkRequest.swift; sourceTree = "<group>"; };
        1355ABF92A4BE9FF002B25E4 /* WelfareCouponsSubListVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WelfareCouponsSubListVC.swift; sourceTree = "<group>"; };
        1355ABFB2A4C15C7002B25E4 /* RechargeRecordVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RechargeRecordVC.swift; sourceTree = "<group>"; };
        1355ABFC2A4C15C7002B25E4 /* RechargeRecordVC.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = RechargeRecordVC.xib; sourceTree = "<group>"; };
@@ -294,6 +303,10 @@
        136FD9AC2A4C2F0500933B7C /* RechargeItemCCell.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = RechargeItemCCell.xib; sourceTree = "<group>"; };
        136FD9AF2A4C354000933B7C /* WelfareRedeemGoodsDetailVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WelfareRedeemGoodsDetailVC.swift; sourceTree = "<group>"; };
        136FD9B02A4C354000933B7C /* WelfareRedeemGoodsDetailVC.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = WelfareRedeemGoodsDetailVC.xib; sourceTree = "<group>"; };
        1375463F2A57F545001FA77A /* UserModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserModel.swift; sourceTree = "<group>"; };
        137546422A57F56F001FA77A /* CommonModels.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CommonModels.swift; sourceTree = "<group>"; };
        137546442A58038B001FA77A /* BaseTableView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BaseTableView.swift; sourceTree = "<group>"; };
        1375464A2A581716001FA77A /* HomeModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HomeModel.swift; sourceTree = "<group>"; };
        1376A6932A4A765700D4C851 /* StudentInfo_3_TCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StudentInfo_3_TCell.swift; sourceTree = "<group>"; };
        1376A6942A4A765700D4C851 /* StudentInfo_3_TCell.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = StudentInfo_3_TCell.xib; sourceTree = "<group>"; };
        1376A6972A4A7B7A00D4C851 /* StudentCourseDetailVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StudentCourseDetailVC.swift; sourceTree = "<group>"; };
@@ -386,6 +399,7 @@
        13D7D6222A4EBBCF000136BD /* SearchStoreTCell.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = SearchStoreTCell.xib; sourceTree = "<group>"; };
        13EC6DDA2A493D23009FC09A /* WelfareCoinCCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WelfareCoinCCell.swift; sourceTree = "<group>"; };
        13EC6DDB2A493D23009FC09A /* WelfareCoinCCell.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = WelfareCoinCCell.xib; sourceTree = "<group>"; };
        13FB93B82A5C028D009F558A /* FinanceTrafer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FinanceTrafer.swift; sourceTree = "<group>"; };
        13FBB8D42A4ED96C00FF70DB /* SearchStoreDetailFeedbackVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SearchStoreDetailFeedbackVC.swift; sourceTree = "<group>"; };
        13FBB8D52A4ED96C00FF70DB /* SearchStoreDetailFeedbackVC.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = SearchStoreDetailFeedbackVC.xib; sourceTree = "<group>"; };
        13FBD7802A4AD62100037156 /* StudentMentalListVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StudentMentalListVC.swift; sourceTree = "<group>"; };
@@ -559,6 +573,39 @@
            path = TCell;
            sourceTree = "<group>";
        };
        1353D5722A56CA0A00539FCA /* Network */ = {
            isa = PBXGroup;
            children = (
                1353D5732A56CA0A00539FCA /* Services.swift */,
                1353D5742A56CA0A00539FCA /* NetworkRequest.swift */,
            );
            path = Network;
            sourceTree = "<group>";
        };
        1375463E2A57F538001FA77A /* ViewModel */ = {
            isa = PBXGroup;
            children = (
                1375463F2A57F545001FA77A /* UserModel.swift */,
            );
            path = ViewModel;
            sourceTree = "<group>";
        };
        137546412A57F564001FA77A /* Model */ = {
            isa = PBXGroup;
            children = (
                137546422A57F56F001FA77A /* CommonModels.swift */,
            );
            path = Model;
            sourceTree = "<group>";
        };
        137546492A58170A001FA77A /* Model */ = {
            isa = PBXGroup;
            children = (
                1375464A2A581716001FA77A /* HomeModel.swift */,
            );
            path = Model;
            sourceTree = "<group>";
        };
        1376A69B2A4A7C5000D4C851 /* Resources */ = {
            isa = PBXGroup;
            children = (
@@ -673,6 +720,14 @@
            path = CCell;
            sourceTree = "<group>";
        };
        13FB93B72A5C0270009F558A /* Category */ = {
            isa = PBXGroup;
            children = (
                13FB93B82A5C028D009F558A /* FinanceTrafer.swift */,
            );
            path = Category;
            sourceTree = "<group>";
        };
        67BBE8279EFA21B415F5EE09 /* Pods */ = {
            isa = PBXGroup;
            children = (
@@ -708,6 +763,7 @@
                13801CC62A4D294D0041454D /* ChooseNumberView.swift */,
                13801CC82A4D29740041454D /* ChooseNumberView.xib */,
                1304B8572A4EAEBA000D4F2E /* CommonBannerView.swift */,
                137546442A58038B001FA77A /* BaseTableView.swift */,
            );
            path = View;
            sourceTree = "<group>";
@@ -778,6 +834,10 @@
        8D8400D02A2F1430003AF6A2 /* WanPai */ = {
            isa = PBXGroup;
            children = (
                13FB93B72A5C0270009F558A /* Category */,
                137546412A57F564001FA77A /* Model */,
                1375463E2A57F538001FA77A /* ViewModel */,
                1353D5722A56CA0A00539FCA /* Network */,
                1376A69B2A4A7C5000D4C851 /* Resources */,
                8DFA9B782A31722300E99281 /* Root */,
                8DAEB5532A30629500814766 /* Common */,
@@ -982,6 +1042,7 @@
        8DFA9B812A31729000E99281 /* Home */ = {
            isa = PBXGroup;
            children = (
                137546492A58170A001FA77A /* Model */,
                8D4905A62A31A6D400E38513 /* CCell */,
                8DFA9B822A3172A300E99281 /* VC */,
            );
@@ -1371,7 +1432,9 @@
                8D710F6D2A31897C0031E2D1 /* WaterFallFlowLayout.swift in Sources */,
                13FBD7842A4ADD0600037156 /* StudentMentalTCell.swift in Sources */,
                8DA51DFA2A32C6C10085F4BA /* StoresChooseView.swift in Sources */,
                137546432A57F56F001FA77A /* CommonModels.swift in Sources */,
                1393B3962A4AD03A00B73072 /* CourseExerciseTCell.swift in Sources */,
                137546402A57F545001FA77A /* UserModel.swift in Sources */,
                13019C7D2A42ADA2004880CD /* CourseInfoVC.swift in Sources */,
                138D8B8E2A3FFE36009DCA9E /* YardListVC.swift in Sources */,
                13BEEAEA2A4D92A200685667 /* ExchangeRecordTCell.swift in Sources */,
@@ -1395,8 +1458,10 @@
                1376A6A12A4A7E1E00D4C851 /* CourseChargeTCell.swift in Sources */,
                13AFABC12A4AE3DC001FEA16 /* StudentRemarkListVC.swift in Sources */,
                8D6D58D12A39906F0003CFE6 /* ActivitySignupListSubVC.swift in Sources */,
                1375464B2A581716001FA77A /* HomeModel.swift in Sources */,
                8D70178D2A330E5700473C40 /* CourseDetailVC.swift in Sources */,
                1355ABFD2A4C15C7002B25E4 /* RechargeRecordVC.swift in Sources */,
                1353D5762A56CA0A00539FCA /* NetworkRequest.swift in Sources */,
                13B640C02A54108B00EA33ED /* UploadImgCCell.swift in Sources */,
                130E40262A4EC029003A3D75 /* SearchStoreDetailVC.swift in Sources */,
                139A39F02A41374100737AFB /* YardBookingSubListVC.swift in Sources */,
@@ -1408,6 +1473,7 @@
                1330DE3B2A4D390700106D69 /* CoinStoreCenterVC.swift in Sources */,
                1387B6752A4ACA1000BF2F2E /* CourseBooking_1_TCell.swift in Sources */,
                1304B85C2A4EB0F8000D4F2E /* SearchBannerCCell.swift in Sources */,
                137546452A58038B001FA77A /* BaseTableView.swift in Sources */,
                1387B6712A4AC9C000BF2F2E /* CourseBookingTCell.swift in Sources */,
                8D8400E92A2F14A3003AF6A2 /* LoginVC.swift in Sources */,
                1376A6992A4A7B7B00D4C851 /* StudentCourseDetailVC.swift in Sources */,
@@ -1437,6 +1503,7 @@
                8D79A58F2A3957420029874B /* StudentInfo_2_TCell.swift in Sources */,
                131732BA2A405EF800F722AF /* CalendarDateTimeTCell.swift in Sources */,
                8D6C50232A372B21007EC2D9 /* IDCardView.swift in Sources */,
                1353D5752A56CA0A00539FCA /* Services.swift in Sources */,
                13801CBE2A4D20D20041454D /* ChooseStoreView.swift in Sources */,
                137801932A3B0D3C00414959 /* CourseOnlineCCell.swift in Sources */,
                136FD9AD2A4C2F0500933B7C /* RechargeItemCCell.swift in Sources */,
@@ -1459,6 +1526,7 @@
                1304B8582A4EAEBA000D4F2E /* CommonBannerView.swift in Sources */,
                8D86DE852A3307A400A754EF /* CourseSubTypeView.swift in Sources */,
                8D79A5932A395BF40029874B /* ActivityStudentListVC.swift in Sources */,
                13FB93B92A5C028D009F558A /* FinanceTrafer.swift in Sources */,
                8D6E54D12A381CB000D750CE /* ActivityDetailVC.swift in Sources */,
                8D5C15062A31861D00A8BCC9 /* TapBtn.swift in Sources */,
            );
@@ -1613,12 +1681,14 @@
                "DEVELOPMENT_TEAM[sdk=iphoneos*]" = 2MWV8K39DV;
                GENERATE_INFOPLIST_FILE = YES;
                INFOPLIST_FILE = WanPai/Info.plist;
                INFOPLIST_KEY_CFBundleDisplayName = "玩湃";
                INFOPLIST_KEY_NSLocationWhenInUseUsageDescription = "$(PRODUCT_NAME)需要使用使用定位,来推荐、搜索您附近的门店";
                INFOPLIST_KEY_CFBundleDisplayName = "玩湃生活";
                INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.sports";
                INFOPLIST_KEY_NSLocationWhenInUseUsageDescription = "WanPai需要使用使用定位,来推荐、搜索您附近的门店";
                INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES;
                INFOPLIST_KEY_UILaunchStoryboardName = LaunchScreen;
                INFOPLIST_KEY_UIMainStoryboardFile = Main;
                INFOPLIST_KEY_UISupportedInterfaceOrientations = UIInterfaceOrientationPortrait;
                INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight UIInterfaceOrientationPortrait";
                IPHONEOS_DEPLOYMENT_TARGET = 13.0;
                LD_RUNPATH_SEARCH_PATHS = (
                    "$(inherited)",
@@ -1651,12 +1721,14 @@
                "DEVELOPMENT_TEAM[sdk=iphoneos*]" = 2MWV8K39DV;
                GENERATE_INFOPLIST_FILE = YES;
                INFOPLIST_FILE = WanPai/Info.plist;
                INFOPLIST_KEY_CFBundleDisplayName = "玩湃";
                INFOPLIST_KEY_NSLocationWhenInUseUsageDescription = "$(PRODUCT_NAME)需要使用使用定位,来推荐、搜索您附近的门店";
                INFOPLIST_KEY_CFBundleDisplayName = "玩湃生活";
                INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.sports";
                INFOPLIST_KEY_NSLocationWhenInUseUsageDescription = "WanPai需要使用使用定位,来推荐、搜索您附近的门店";
                INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES;
                INFOPLIST_KEY_UILaunchStoryboardName = LaunchScreen;
                INFOPLIST_KEY_UIMainStoryboardFile = Main;
                INFOPLIST_KEY_UISupportedInterfaceOrientations = UIInterfaceOrientationPortrait;
                INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight UIInterfaceOrientationPortrait";
                IPHONEOS_DEPLOYMENT_TARGET = 13.0;
                LD_RUNPATH_SEARCH_PATHS = (
                    "$(inherited)",
WanPai/AppDelegate.swift
@@ -7,6 +7,7 @@
import UIKit
import JQTools
import Alamofire
@main
class AppDelegate: UIResponder, UIApplicationDelegate {
@@ -16,7 +17,7 @@
    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
        Services.startNetworkMonitor()
        return true
    }
@@ -35,7 +36,48 @@
    }
    func application(_ application: UIApplication, supportedInterfaceOrientationsFor window: UIWindow?) -> UIInterfaceOrientationMask {
        return orientation
        if UIDevice.current.userInterfaceIdiom == .pad{
            return .all
        }else{
            return orientation
        }
    }
}
extension AppDelegate{
    func registerAndLoginSuccess(){
        let snapView = screnDelegate?.window?.snapshotView(afterScreenUpdates: true)
        let tabBar = BaseTabBarVC()
        let homeNav = BaseNav(rootViewController: HomeVC())
        homeNav.tabBarItem = UITabBarItem(title: "加入玩湃", image: UIImage(named: "tabbar_home"), selectedImage: UIImage(named: "tabbar_home_s"))
        let clouseNav = BaseNav(rootViewController: CourseVC())
//        let clouseNav = BaseNav(rootViewController: CourseInfoVC())
        clouseNav.tabBarItem = UITabBarItem(title: "开始上课", image: UIImage(named: "tabbar_course"), selectedImage: UIImage(named: "tabbar_course_s"))
        let welfareVCNav = BaseNav(rootViewController: WelfareVC())
        welfareVCNav.tabBarItem = UITabBarItem(title: "使用福利", image: UIImage(named: "tabbar_welfare"), selectedImage: UIImage(named: "tabbar_welfare_s"))
        let searchVCNav = BaseNav(rootViewController: SearchVC())
        searchVCNav.tabBarItem = UITabBarItem(title: "搜索玩湃", image: UIImage(named: "tabbar_search"), selectedImage: UIImage(named: "tabbar_search_s"))
        tabBar.viewControllers = [homeNav,clouseNav,welfareVCNav,searchVCNav]
        screnDelegate?.window?.rootViewController = tabBar
        screnDelegate?.window?.rootViewController?.view.addSubview(snapView!)
        screnDelegate?.window?.makeKeyAndVisible()
        UIView.animate(withDuration: 1.5) {
            snapView?.alpha = 0
            snapView?.transform3D = CATransform3DMakeScale(1.5, 1.5, 1.5)
        } completion: { _ in
            snapView?.removeFromSuperview()
        }
    }
    func needLogin(){
        let nav = LoginNav(rootViewController: LoginVC())
        window?.rootViewController =  nav
        window?.makeKeyAndVisible()
    }
}
WanPai/Assets.xcassets/AppIcon.appiconset/Contents.json
@@ -1,8 +1,75 @@
{
  "images" : [
    {
      "idiom" : "universal",
      "platform" : "ios",
      "filename" : "notification-icon@2x.png",
      "idiom" : "iphone",
      "scale" : "2x",
      "size" : "20x20"
    },
    {
      "filename" : "notification-icon@3x.png",
      "idiom" : "iphone",
      "scale" : "3x",
      "size" : "20x20"
    },
    {
      "filename" : "icon-small.png",
      "idiom" : "iphone",
      "scale" : "1x",
      "size" : "29x29"
    },
    {
      "filename" : "icon-small@2x.png",
      "idiom" : "iphone",
      "scale" : "2x",
      "size" : "29x29"
    },
    {
      "filename" : "icon-small@3x.png",
      "idiom" : "iphone",
      "scale" : "3x",
      "size" : "29x29"
    },
    {
      "filename" : "icon-40@2x.png",
      "idiom" : "iphone",
      "scale" : "2x",
      "size" : "40x40"
    },
    {
      "filename" : "icon-40@3x.png",
      "idiom" : "iphone",
      "scale" : "3x",
      "size" : "40x40"
    },
    {
      "filename" : "icon.png",
      "idiom" : "iphone",
      "scale" : "1x",
      "size" : "57x57"
    },
    {
      "filename" : "icon@2x.png",
      "idiom" : "iphone",
      "scale" : "2x",
      "size" : "57x57"
    },
    {
      "filename" : "icon-60@2x.png",
      "idiom" : "iphone",
      "scale" : "2x",
      "size" : "60x60"
    },
    {
      "filename" : "icon-60@3x.png",
      "idiom" : "iphone",
      "scale" : "3x",
      "size" : "60x60"
    },
    {
      "filename" : "ios-marketing.png",
      "idiom" : "ios-marketing",
      "scale" : "1x",
      "size" : "1024x1024"
    }
  ],
WanPai/Assets.xcassets/AppIcon.appiconset/icon-40@2x.png
WanPai/Assets.xcassets/AppIcon.appiconset/icon-40@3x.png
WanPai/Assets.xcassets/AppIcon.appiconset/icon-60@2x.png
WanPai/Assets.xcassets/AppIcon.appiconset/icon-60@3x.png
WanPai/Assets.xcassets/AppIcon.appiconset/icon-small.png
WanPai/Assets.xcassets/AppIcon.appiconset/icon-small@2x.png
WanPai/Assets.xcassets/AppIcon.appiconset/icon-small@3x.png
WanPai/Assets.xcassets/AppIcon.appiconset/icon.png
WanPai/Assets.xcassets/AppIcon.appiconset/icon@2x.png
WanPai/Assets.xcassets/AppIcon.appiconset/ios-marketing.png
WanPai/Assets.xcassets/AppIcon.appiconset/notification-icon@2x.png
WanPai/Assets.xcassets/AppIcon.appiconset/notification-icon@3x.png
WanPai/Assets.xcassets/Icons/icon_asc.imageset/Contents.json
WanPai/Assets.xcassets/Icons/icon_asc.imageset/icon_aes@2x.png

WanPai/Assets.xcassets/Icons/icon_asc.imageset/icon_aes@3x.png

WanPai/Assets.xcassets/Icons/icon_desc.imageset/Contents.json
WanPai/Assets.xcassets/Icons/icon_desc.imageset/icon_des@2x.png

WanPai/Assets.xcassets/Icons/icon_desc.imageset/icon_des@3x.png

WanPai/Assets.xcassets/Icons/icon_empty.imageset/Contents.json
New file
@@ -0,0 +1,22 @@
{
  "images" : [
    {
      "idiom" : "universal",
      "scale" : "1x"
    },
    {
      "filename" : "icon_empty@2x.png",
      "idiom" : "universal",
      "scale" : "2x"
    },
    {
      "filename" : "icon_empty@3x.png",
      "idiom" : "universal",
      "scale" : "3x"
    }
  ],
  "info" : {
    "author" : "xcode",
    "version" : 1
  }
}
WanPai/Assets.xcassets/Icons/icon_empty.imageset/icon_empty@2x.png
WanPai/Assets.xcassets/Icons/icon_empty.imageset/icon_empty@3x.png
WanPai/Assets.xcassets/Icons/icon_login_pwd.imageset/Contents.json
New file
@@ -0,0 +1,22 @@
{
  "images" : [
    {
      "idiom" : "universal",
      "scale" : "1x"
    },
    {
      "filename" : "icon_login_pwd@2x.png",
      "idiom" : "universal",
      "scale" : "2x"
    },
    {
      "filename" : "icon_login_pwd@3x.png",
      "idiom" : "universal",
      "scale" : "3x"
    }
  ],
  "info" : {
    "author" : "xcode",
    "version" : 1
  }
}
WanPai/Assets.xcassets/Icons/icon_login_pwd.imageset/icon_login_pwd@2x.png
WanPai/Assets.xcassets/Icons/icon_login_pwd.imageset/icon_login_pwd@3x.png
WanPai/Base.lproj/LaunchScreen.storyboard
@@ -1,8 +1,11 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="13122.16" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="01J-lp-oVM">
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="21701" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="01J-lp-oVM">
    <device id="retina6_12" orientation="portrait" appearance="light"/>
    <dependencies>
        <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="13104.12"/>
        <deployment identifier="iOS"/>
        <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="21679"/>
        <capability name="Safe area layout guides" minToolsVersion="9.0"/>
        <capability name="System colors in document resources" minToolsVersion="11.0"/>
        <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
    </dependencies>
    <scenes>
@@ -11,10 +14,19 @@
            <objects>
                <viewController id="01J-lp-oVM" sceneMemberID="viewController">
                    <view key="view" contentMode="scaleToFill" id="Ze5-6b-2t3">
                        <rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
                        <rect key="frame" x="0.0" y="0.0" width="393" height="852"/>
                        <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
                        <color key="backgroundColor" xcode11CocoaTouchSystemColor="systemBackgroundColor" cocoaTouchSystemColor="whiteColor"/>
                        <subviews>
                            <imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="icon_LOGO" translatesAutoresizingMaskIntoConstraints="NO" id="wQN-pJ-fP4">
                                <rect key="frame" x="122.66666666666669" y="124" width="148" height="72"/>
                            </imageView>
                        </subviews>
                        <viewLayoutGuide key="safeArea" id="6Tk-OE-BBY"/>
                        <color key="backgroundColor" systemColor="systemBackgroundColor"/>
                        <constraints>
                            <constraint firstItem="wQN-pJ-fP4" firstAttribute="top" secondItem="6Tk-OE-BBY" secondAttribute="top" constant="65" id="Vvc-P2-aee"/>
                            <constraint firstItem="wQN-pJ-fP4" firstAttribute="centerX" secondItem="6Tk-OE-BBY" secondAttribute="centerX" id="wCQ-9d-evQ"/>
                        </constraints>
                    </view>
                </viewController>
                <placeholder placeholderIdentifier="IBFirstResponder" id="iYj-Kq-Ea1" userLabel="First Responder" sceneMemberID="firstResponder"/>
@@ -22,4 +34,10 @@
            <point key="canvasLocation" x="53" y="375"/>
        </scene>
    </scenes>
    <resources>
        <image name="icon_LOGO" width="148" height="72"/>
        <systemColor name="systemBackgroundColor">
            <color white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
        </systemColor>
    </resources>
</document>
WanPai/Base/BaseVC.swift
@@ -9,10 +9,13 @@
import RxSwift
import RxRelay
import RxCocoa
import JQTools
class BaseVC: UIViewController {
    var disposeBag:DisposeBag!
    let refreshStatus = BehaviorSubject(value: RefreshStatus.others)
    var yy_popBlock:(() -> Void)?
    open var nav_back_img:UIImage = UIImage.init(named: "btn_back") ?? UIImage.init() {
        didSet {
WanPai/Category/FinanceTrafer.swift
New file
@@ -0,0 +1,30 @@
//
//  FinanceTrafer.swift
//  WanPai
//
//  Created by 无故事王国 on 2023/7/10.
//
import Foundation
extension Int{
    func currency()->String{
        let formatter = NumberFormatter()
        formatter.numberStyle = .decimal
        formatter.groupingSeparator = ","
        formatter.groupingSize = 3
        formatter.positivePrefix = "¥"
        return formatter.string(from: NSNumber(value: self)) ?? "¥0"
    }
}
extension Double{
    func currency()->String{
        let formatter = NumberFormatter()
        formatter.numberStyle = .decimal
        formatter.groupingSeparator = ","
        formatter.groupingSize = 3
        formatter.positivePrefix = "¥"
        return formatter.string(from: NSNumber(value: Darwin.floor(self))) ?? "¥0"
    }
}
WanPai/Common/View/AgreentView.swift
@@ -7,21 +7,21 @@
import UIKit
import JQTools
import RxSwift
import WebKit
class AgreentView: UIView,JQNibView{
    enum AgreentType {
        case user
        case safe
        case privacy
    }
    @IBOutlet weak var label_title: UILabel!
    @IBOutlet weak var view_container: UIView!
    @IBOutlet weak var webView: WKWebView!
    @IBOutlet weak var bottom_cons: NSLayoutConstraint!
    private var type:AgreentType!
    private let disposeBag = DisposeBag()
    
    override func awakeFromNib() {
        super.awakeFromNib()
        webView.backgroundColor = .white
        bottom_cons.constant = -(JQ_ScreenH - JQ_ScreenW * 0.9)
        layoutIfNeeded()
    }
@@ -31,13 +31,19 @@
        let alertView = AgreentView.jq_loadNibView()
        alertView.frame = screnDelegate?.window?.frame ?? .zero
        alertView.type = type
        alertView.label_title.text = type.titleStr
        screnDelegate?.window?.addSubview(alertView)
        alertView.bottom_cons.constant = 0
        
        UIView.animate(withDuration: 0.4) {
            alertView.layoutIfNeeded()
        }
        Services.queryProtocol(type,progress: false).subscribe(onNext: { result in
            if let text = result.data?.jq_wrapHtml(){
                alertView.webView.loadHTMLString(text, baseURL: nil)
            }
        }).disposed(by: alertView.disposeBag)
    }
    
    
WanPai/Common/View/AgreentView.xib
@@ -1,8 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="21507" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="21701" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
    <device id="retina6_12" orientation="portrait" appearance="light"/>
    <dependencies>
        <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="21505"/>
        <deployment identifier="iOS"/>
        <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="21679"/>
        <capability name="Safe area layout guides" minToolsVersion="9.0"/>
        <capability name="System colors in document resources" minToolsVersion="11.0"/>
        <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
@@ -63,7 +64,9 @@
            </constraints>
            <connections>
                <outlet property="bottom_cons" destination="mzT-t7-Ph5" id="s3O-fR-X42"/>
                <outlet property="label_title" destination="G2G-hL-VpJ" id="B9O-8S-yCu"/>
                <outlet property="view_container" destination="RL2-Pc-fjv" id="r9b-Cn-uAS"/>
                <outlet property="webView" destination="EJM-vb-bxZ" id="hZC-uh-Xle"/>
            </connections>
            <point key="canvasLocation" x="20.610687022900763" y="20.422535211267608"/>
        </view>
WanPai/Common/View/BaseTableView.swift
New file
@@ -0,0 +1,50 @@
//
//  BaseTableView.swift
//  WanPai
//
//  Created by 无故事王国 on 2023/7/7.
//
import UIKit
import EmptyDataSet_Swift
class BaseTableView:UITableView{
    public func jq_setEmptyView( _ noticeStr:String? = nil,image:UIImage? = UIImage(named: "icon_empty"),foregroundColor:UIColor = UIColor.gray.withAlphaComponent(0.5),clouse:((EmptyDataSetView)->Void)? = nil) {
        self.separatorStyle = .none
        self.emptyDataSetView { (emptyDataSetView) in
            emptyDataSetView.titleLabelString(NSAttributedString.init(string: (noticeStr != nil) ? noticeStr! : "暂无数据", attributes: [.font:UIFont.systemFont(ofSize: 16), .foregroundColor:foregroundColor as Any]))
                .image(image)
                .dataSetBackgroundColor(UIColor.white)
                .verticalOffset(0)
                .verticalSpace(15)
                .shouldDisplay(true)
                .shouldFadeIn(true)
                .isTouchAllowed(true)
                .isScrollAllowed(true)
                .didTapContentView {
                }
            clouse?(emptyDataSetView)
        }
    }
}
class BaseCollectionView:UICollectionView{
    public func jq_setEmptyView( _ noticeStr:String? = nil,image:UIImage? = UIImage(named: "icon_empty"),foregroundColor:UIColor = UIColor.gray.withAlphaComponent(0.5),clouse:((EmptyDataSetView)->Void)? = nil) {
        self.emptyDataSetView { (emptyDataSetView) in
            emptyDataSetView.titleLabelString(NSAttributedString.init(string: (noticeStr != nil) ? noticeStr! : "暂无数据", attributes: [.font:UIFont.systemFont(ofSize: 16), .foregroundColor:foregroundColor as Any]))
                .image(image)
                .dataSetBackgroundColor(UIColor.white)
                .verticalOffset(0)
                .verticalSpace(15)
                .shouldDisplay(true)
                .shouldFadeIn(true)
                .isTouchAllowed(true)
                .isScrollAllowed(true)
                .didTapContentView {
                }
            clouse?(emptyDataSetView)
        }
    }
}
WanPai/Common/View/CommonBannerView.swift
@@ -8,192 +8,192 @@
import UIKit
import SDWebImage
class CommonBannerView: UIView,UIScrollViewDelegate {
        //图⽚⽔平放置到scrollView上
    private var scrollView:UIScrollView = UIScrollView()
        //⼩圆点标识
    private var pageControl:UIPageControl = UIPageControl()
    private var imageViews:Array = Array<UIImageView>()
        //图⽚集合
    private var images:Array<String> = []
    private var type:ImageType?
    private var width:CGFloat = 0
    private var height:CGFloat = 0
    private var currIndex = 0
    private var clickBlock :(Int)->Void = {index in}
    private var timer:Timer?
        // 默认⾃动播放 设置为false只能⼿动滑动
    var isAuto = true
        // 轮播间隔时间 默认6秒可以⾃⼰修改
    var interval:Double = 6
    private var startOffsetX:CGFloat = 0
    override func layoutSubviews() {
        super.layoutSubviews()
    }
    public func setImages(images:Array<String>,type:ImageType
                          = .Image,imageClickBlock:@escaping (Int) -> Void) {
        self.type = type
        self.images = images
        self.clickBlock = imageClickBlock
        self.initLayout()
    }
    private func initLayout(){
        if(self.images.count == 0){
            return
        }
        width = self.bounds.width
        height = self.bounds.height
        scrollView.frame = self.bounds
        scrollView.contentSize = CGSize(width:width * CGFloat(images.count +
                                                              2),height:height)
        scrollView.contentOffset = CGPoint(x:width,y:0)
        scrollView.isUserInteractionEnabled = true
        scrollView.isPagingEnabled = true
        scrollView.showsHorizontalScrollIndicator = false
        scrollView.delegate = self
        self.addSubview(scrollView)
        var image = UIImageView()
        image.frame = CGRect(x:0,y:0,width:width,height:height)
        image.contentMode = .scaleToFill
        image.isUserInteractionEnabled = true
        setImage(image: image, index: images.count - 1)
        scrollView.addSubview(image)
        for i in 1 ... images.count{
            let image = UIImageView()
            image.frame = CGRect(x:width *
                                 CGFloat(i),y:0,width:width,height:height)
            image.contentMode = .scaleToFill
            image.isUserInteractionEnabled = true
            scrollView.addSubview(image)
            setImage(image: image, index: i - 1)
            addTapGesWithImage(image: image)
        }
        image = UIImageView()
        image.frame = CGRect(x:width * CGFloat(images.count +
                                               1),y:0,width:width,height:height)
        image.contentMode = .scaleToFill
        image.isUserInteractionEnabled = true
        scrollView.addSubview(image)
        setImage(image: image, index: 0)
        pageControl.center = CGPoint(x:width/2,y:height - CGFloat(15))
        pageControl.isEnabled = true
        pageControl.numberOfPages = images.count
        pageControl.currentPageIndicatorTintColor = UIColor.green
        pageControl.pageIndicatorTintColor = UIColor.gray
        pageControl.isUserInteractionEnabled = false
        self.addSubview(pageControl)
            //当前显示的只有 center_image 其他两个只是⽤来增加滑动时效果⽽已,不
            //addTapGesWithImage(image: center_image)
        if(isAuto){
            openTimer()
        }
        setCurrent(currIndex: 0)
    }
    private func setImage(image:UIImageView,index:Int){
        if(type == .Image){
            image.image = UIImage.init(named:images[index])
        }else{
            image.sd_setImage(with: URL(string: images[index]))
        }
    }
    func setCurrent(currIndex:Int) {
        if(currIndex < 0){
            self.currIndex = images.count - 1
        }else{
            self.currIndex = currIndex
        }
        pageControl.currentPage = self.currIndex
        scrollView.setContentOffset(CGPoint(x:width * CGFloat(self.currIndex +
                                                              1),y:0), animated: false)
    }
        //给图⽚添加点击⼿势
    private func addTapGesWithImage(image:UIImageView) {
        let tap = UITapGestureRecognizer(target: self, action: #selector(tap(_:)))
        image.isUserInteractionEnabled = true //让控件可以触发交互事件
        image.contentMode = .scaleToFill
            // image.clipsToBounds = true //超出⽗控件的部分不显示
        image.addGestureRecognizer(tap)
    }
        //点击图⽚,调⽤block
    @objc func tap(_ ges:UITapGestureRecognizer) {
        clickBlock((ges.view?.tag)!)
    }
    func scrollViewDidScroll(_ scrollView: UIScrollView) {
    }
    func scrollViewWillBeginDragging(_ scrollView: UIScrollView) {
        startOffsetX = scrollView.contentOffset.x
        closeTimer()
    }
    func scrollViewDidEndDragging(_ scrollView: UIScrollView, willDecelerate
                                  decelerate: Bool) {
    }
    func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) {
        if(scrollView.contentOffset.x > startOffsetX){
            currIndex = (currIndex + 1) % images.count
        }else{
            currIndex = (currIndex - 1) % images.count
        }
        setCurrent(currIndex: currIndex)
        openTimer()
    }
    func openTimer(){
        if(isAuto){
            closeTimer()
            timer = Timer.scheduledTimer(timeInterval: interval, target: self, selector:
                                            #selector(startAutoScroll), userInfo: nil, repeats: true)
        }
    }
    func closeTimer(){
        if(timer != nil){
            timer?.invalidate()
            timer = nil
        }
    }
    @objc func startAutoScroll(){
        if(isDisplayInScreen()){
            setCurrent(currIndex: (currIndex + 1) % images.count)
        }
    }
    func isDisplayInScreen() -> Bool{
        if(self.window == nil){
            return false
        }
        return true
    }
}
enum ImageType{
    case Image //本地图⽚
    case URL //URL
}
//class CommonBannerView: UIView,UIScrollViewDelegate {
//
//        //图⽚⽔平放置到scrollView上
//    private var scrollView:UIScrollView = UIScrollView()
//        //⼩圆点标识
//    private var pageControl:UIPageControl = UIPageControl()
//    private var imageViews:Array = Array<UIImageView>()
//
//
//        //图⽚集合
//    private var images:Array<String> = []
//    private var type:ImageType?
//
//    private var width:CGFloat = 0
//    private var height:CGFloat = 0
//
//    private var currIndex = 0
//    private var clickBlock :(Int)->Void = {index in}
//
//    private var timer:Timer?
//
//        // 默认⾃动播放 设置为false只能⼿动滑动
//    var isAuto = true
//        // 轮播间隔时间 默认6秒可以⾃⼰修改
//    var interval:Double = 6
//
//    private var startOffsetX:CGFloat = 0
//
//    override func layoutSubviews() {
//        super.layoutSubviews()
//    }
//
//    public func setImages(images:Array<String>,type:ImageType
//                          = .Image,imageClickBlock:@escaping (Int) -> Void) {
//        self.type = type
//        self.images = images
//        self.clickBlock = imageClickBlock
//        self.initLayout()
//    }
//
//    private func initLayout(){
//        if(self.images.count == 0){
//            return
//        }
//
//        width = self.bounds.width
//        height = self.bounds.height
//
//        scrollView.frame = self.bounds
//        scrollView.contentSize = CGSize(width:width * CGFloat(images.count +
//                                                              2),height:height)
//        scrollView.contentOffset = CGPoint(x:width,y:0)
//        scrollView.isUserInteractionEnabled = true
//        scrollView.isPagingEnabled = true
//        scrollView.showsHorizontalScrollIndicator = false
//        scrollView.delegate = self
//        self.addSubview(scrollView)
//
//        var image = UIImageView()
//        image.frame = CGRect(x:0,y:0,width:width,height:height)
//        image.contentMode = .scaleToFill
//        image.isUserInteractionEnabled = true
//        setImage(image: image, index: images.count - 1)
//        scrollView.addSubview(image)
//        for i in 1 ... images.count{
//            let image = UIImageView()
//            image.frame = CGRect(x:width *
//                                 CGFloat(i),y:0,width:width,height:height)
//            image.contentMode = .scaleToFill
//            image.isUserInteractionEnabled = true
//            scrollView.addSubview(image)
//            setImage(image: image, index: i - 1)
//            addTapGesWithImage(image: image)
//        }
//        image = UIImageView()
//        image.frame = CGRect(x:width * CGFloat(images.count +
//                                               1),y:0,width:width,height:height)
//        image.contentMode = .scaleToFill
//        image.isUserInteractionEnabled = true
//        scrollView.addSubview(image)
//        setImage(image: image, index: 0)
//
//        pageControl.center = CGPoint(x:width/2,y:height - CGFloat(15))
//        pageControl.isEnabled = true
//        pageControl.numberOfPages = images.count
//        pageControl.currentPageIndicatorTintColor = UIColor.green
//        pageControl.pageIndicatorTintColor = UIColor.gray
//        pageControl.isUserInteractionEnabled = false
//        self.addSubview(pageControl)
//
//            //当前显示的只有 center_image 其他两个只是⽤来增加滑动时效果⽽已,不
//            //addTapGesWithImage(image: center_image)
//        if(isAuto){
//            openTimer()
//        }
//        setCurrent(currIndex: 0)
//    }
//
//    private func setImage(image:UIImageView,index:Int){
//        if(type == .Image){
//            image.image = UIImage.init(named:images[index])
//        }else{
//            image.sd_setImage(with: URL(string: images[index]))
//        }
//    }
//
//    func setCurrent(currIndex:Int) {
//        if(currIndex < 0){
//            self.currIndex = images.count - 1
//        }else{
//            self.currIndex = currIndex
//        }
//        pageControl.currentPage = self.currIndex
//        scrollView.setContentOffset(CGPoint(x:width * CGFloat(self.currIndex +
//                                                              1),y:0), animated: false)
//    }
//
//        //给图⽚添加点击⼿势
//    private func addTapGesWithImage(image:UIImageView) {
//        let tap = UITapGestureRecognizer(target: self, action: #selector(tap(_:)))
//        image.isUserInteractionEnabled = true //让控件可以触发交互事件
//        image.contentMode = .scaleToFill
//            // image.clipsToBounds = true //超出⽗控件的部分不显示
//        image.addGestureRecognizer(tap)
//    }
//
//        //点击图⽚,调⽤block
//    @objc func tap(_ ges:UITapGestureRecognizer) {
//        clickBlock((ges.view?.tag)!)
//    }
//
//    func scrollViewDidScroll(_ scrollView: UIScrollView) {
//
//    }
//
//    func scrollViewWillBeginDragging(_ scrollView: UIScrollView) {
//        startOffsetX = scrollView.contentOffset.x
//        closeTimer()
//    }
//
//    func scrollViewDidEndDragging(_ scrollView: UIScrollView, willDecelerate
//                                  decelerate: Bool) {
//    }
//
//    func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) {
//        if(scrollView.contentOffset.x > startOffsetX){
//            currIndex = (currIndex + 1) % images.count
//        }else{
//            currIndex = (currIndex - 1) % images.count
//        }
//        setCurrent(currIndex: currIndex)
//        openTimer()
//    }
//
//    func openTimer(){
//        if(isAuto){
//            closeTimer()
//            timer = Timer.scheduledTimer(timeInterval: interval, target: self, selector:
//                                            #selector(startAutoScroll), userInfo: nil, repeats: true)
//        }
//    }
//
//    func closeTimer(){
//        if(timer != nil){
//            timer?.invalidate()
//            timer = nil
//        }
//    }
//
//
//    @objc func startAutoScroll(){
//        if(isDisplayInScreen()){
//            setCurrent(currIndex: (currIndex + 1) % images.count)
//        }
//    }
//
//    func isDisplayInScreen() -> Bool{
//        if(self.window == nil){
//            return false
//        }
//        return true
//    }
//
//}
//enum ImageType{
//    case Image //本地图⽚
//    case URL //URL
//
//}
WanPai/Config/Def.swift
@@ -8,6 +8,12 @@
import Foundation
import UIKit
import JQTools
import SVProgressHUD
import QMUIKit
let SHAKEY = "BT7NPhA0f775uzcUuftWjCE1TYZlWmHZ"
let app = UIApplication.shared.delegate as! AppDelegate
@@ -43,3 +49,17 @@
    print("⚠️⚠️⚠️INFO: \(file)  \(function) [Line: \(line)]: \(items)",separator);
#endif
}
    //提示框
func alert(msg: String) {
    SVProgressHUD.showInfo(withStatus: msg)
}
func alertError(msg:String){
    SVProgressHUD.setMinimumDismissTimeInterval(1.5)
    SVProgressHUD.showError(withStatus: msg)
}
func alertSuccess(msg:String){
    SVProgressHUD.showSuccess(withStatus: msg)
}
WanPai/Config/Enums.swift
@@ -6,7 +6,14 @@
//
import Foundation
import HandyJSON
/// 登录类型
enum LoginType{
    case pwd,smsCode
}
/// 支付方式
enum PayType:Int{
    case aliPay = 0
    case wechat = 1
@@ -18,3 +25,124 @@
    case course
    case activity
}
/// 获取短信验证码类型
enum GetSMSCodeType:Int{
    case login = 1
    case register = 2
    case updatePwd = 3
    case forgotPwd = 4
    var titleStr:String{
        switch self {
            case .login:
                return "登录"
            case .register:
                return "注册"
            case .updatePwd:
                return "修改密码"
            case .forgotPwd:
                return "忘记密码"
        }
    }
}
enum AgreentType:Int {
    case user = 1
    case safe = 3
    case privacy = 2
    var titleStr:String{
        switch self{
            case .privacy:return "隐私协议"
            case .safe:return "运动安全告知书"
            case .user:return "用户协议"
        }
    }
}
enum SystemImgType:Int{
    case notStudent = 1
    case becomeVip = 2
    case myCoupon = 3
    case shoppingOnline = 4
    case welfareWeekly = 5
    case freeToday = 6
}
enum HomeItemType:Int,HandyJSONEnum{
    //1=报名玩湃课程,2=预约场地,3=报名赛事及活动,4=免费福利,5=线上课程积分,6=购买优惠门票,7=看视频得奖励,8=智慧球场)
    case none = 0
    case course = 1
    case booking = 2
    case activity = 3
    case welfare = 4
    case coin = 5
    case ticket = 6
    case video = 7
    case wisdomCourt = 8
    var defaultImg:UIImage{
        switch self {
            case .none:
                return UIImage()
            case .course:
                return UIImage(named: "b_1")!
            case .booking:
                return UIImage(named: "b_5")!
            case .activity:
                return UIImage(named: "b_2")!
            case .welfare:
                return UIImage(named: "b_6")!
            case .coin:
                return UIImage(named: "b_4")!
            case .ticket:
                return UIImage(named: "b_8")!
            case .video:
                return UIImage(named: "b_3")!
            case .wisdomCourt:
                return UIImage(named: "b_7")!
        }
    }
    var defaultHeight:Double {
        switch self {
            case .none:
                return 185
            case .course:
                return 288
            case .booking:
                return 288
            case .activity:
                return 185
            case .welfare:
                return 185
            case .coin:
                return 185
            case .ticket:
                return 185
            case .video:
                return 288
            case .wisdomCourt:
                return 288
        }
    }
}
enum SortType:String{
    case asc = "asc"
    case desc = "desc"
    var img:UIImage{
        switch self{
            case .asc:return UIImage(named: "icon_asc")!
            case .desc:return UIImage(named: "icon_desc")!
        }
    }
}
enum PaymentType:Int,HandyJSONEnum{
    case cash = 1 //现金
    case coin = 2 //玩湃币
}
WanPai/Info.plist
@@ -2,6 +2,22 @@
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>CFBundleURLTypes</key>
    <array>
        <dict>
            <key>CFBundleTypeRole</key>
            <string>Editor</string>
            <key>CFBundleURLSchemes</key>
            <array>
                <string>weparklife</string>
            </array>
        </dict>
    </array>
    <key>NSAppTransportSecurity</key>
    <dict>
        <key>NSAllowsArbitraryLoads</key>
        <true/>
    </dict>
    <key>UIAppFonts</key>
    <array>
        <string>Impact.ttf</string>
WanPai/Model/CommonModels.swift
New file
@@ -0,0 +1,57 @@
    //
    //  CommonModels.swift
    //  WanPai
    //
    //  Created by 无故事王国 on 2023/7/7.
    //
import HandyJSON
struct CourseItemModel:HandyJSON{
    var id = 0
    var storeName = ""
    var name = ""
    var coverDrawing = ""
    var classStartTime = ""
    var applicantsNumber = 0
    var payType:PaymentType = .cash
    var originalPrice:Double?
    var vipPrice:Double = 0
    var paymentPrice:Double = 0
    var playPaiCoin:Int = 0
    var distance:Double = 0
}
struct CourseDetailModel:HandyJSON {
    var coverDrawing: String = ""
    var detailDrawing: String = ""
    var distance: Double = 0
    var id: Int = 0
    var introduceDrawing: String = ""
    var lat: String = ""
    var list = [CourseDetailListModel]()
    var lon: String = ""
    var name: String = ""
    var storeAddress: String = ""
    var storeCoverDrawing: String = ""
    var storeName: String = ""
    var student: CourseDetailStudentModel?
    var times: String = ""
    var weeks = [String]()
}
struct CourseDetailListModel:HandyJSON {
    var classHours: Int = 0
    var id: Int = 0
    var originalPrice: Double = 0
    var paymentPrice: Double = 0
    var payType: Int = 0
    var playPaiCoin: Int = 0
    var vipPrice: Double = 0
}
struct CourseDetailStudentModel:HandyJSON {
    var age: Int = 0
    var id: Int = 0
    var phone: String = ""
}
WanPai/Network/NetworkRequest.swift
New file
@@ -0,0 +1,375 @@
    //
    //  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
    // 假设这是服务端返回的统一定义的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{
}
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: String) -> ParamsAppender {
        if value.isEmpty{return self}
        params += ["\(key)":"\(value)"]
        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 {
            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()
        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))"]
        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(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) -> 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 {SVProgressHUD.show()}
            var headers = HTTPHeaders()
            if let token = UserViewModel.getToken(){
                headers.add(name: "Authorization", value: "Bearer" + " " + token)
                LogInfo("USER_token:\(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)")
                SVProgressHUD.dismiss()
                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)】")
                    }
                    alert(msg: errorString)
                    ob.onError(response.error!)
                    return
                }
                if let data = response.data,let jsonString = String(data: data, encoding: String.Encoding.utf8){
                    if let next = BaseResponse<T>.deserialize(from: jsonString){
                        LogInfo("返回数据:\(jsonString)")
                        switch next.code{
                            case 200:ob.onNext(next)
                            case 600:alertError(msg: "登录失效,请重新登录");ob.onError(NetRequestError.InvaildSession)
                            default:alertError(msg: "\(next.msg)");ob.onError(NetRequestError.Other(next.msg))
                        }
                    }
                }
                ob.onCompleted()
            }
            return Disposables.create{}
        }
    }
//    class func requestData(params: ParamsAppender, method: HTTPMethod, encoding: ParameterEncoding? = nil, progress: Bool = true) -> Observable<Data>{
//        return Observable<Data>.create{ ob in
//            if progress {
//                SVProgressHUD.show()
//            }
//
//            var headers = HTTPHeaders()
//                //            if let token = UserViewModel.getUserInfo()?.token {
//                //                headers.add(name: "Authorization", value: "Bearer" + " " + token)
//                //                LogInfo("USER_token:\(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)")
//                SVProgressHUD.dismiss()
//                if response.error != nil {
//                    LogError("\(response.error!)")
//                    ob.onError(response.error!)
//                }else if let data = response.data{
//                    LogInfo("返回数据:\(data)")
//                    ob.onNext(data)
//                }
//                ob.onCompleted()
//            }
//            return Disposables.create{}
//        }
//    }
//
//        /// 带code请求的
//        /// - Parameters:
//        ///   - params: <#params description#>
//        ///   - method: <#method description#>
//        ///   - progress: <#progress description#>
//        /// - Returns: <#description#>
//    class func requestCode<T: HandyJSON>(params: ParamsAppender,method: HTTPMethod,progress: Bool = true) -> Observable<BaseResponse<T>>{
//        return Observable<BaseResponse<T>>.create{ ob in
//            if progress {
//                SVProgressHUD.show()
//            }
//            sharedSessionManager.request(params.url.absoluteString, method: method, parameters:
//                                            params.done(),encoding: URLEncoding.default).validate().responseData{response in
//                LogInfo("请求地址:\(params.url)")
//                LogInfo("请求参数:\(params.params)")
//                if response.error != nil {
//                    SVProgressHUD.dismiss()
//                    LogInfo("\(response.error!)")
//                    ob.onError(response.error!)
//                }else if let data = response.data,let jsonString = String(data: data, encoding: String.Encoding.utf8){
//
//                    SVProgressHUD.dismiss()
//                    LogInfo("返回数据:\(jsonString)")
//                    if let next = BaseResponse<T>.deserialize(from: jsonString){
//                        ob.onNext(next)
//                    }else{
//                        SVProgressHUD.dismiss()
//                            //                            alert(msg: "请求失败")
//                        LogInfo("error")
//                    }
//                }else{
//                    SVProgressHUD.dismiss()
//                        //                        alert(msg: "请求失败")
//                    LogInfo("Netrequest-Tag:No data")
//                }
//                ob.onCompleted()
//            }
//            return Disposables.create{}
//        }
//    }
//        /// 上传
//        /// - Parameter params: <#params description#>
//    class func upload<T: HandyJSON>(params: ParamsAppender) -> Observable<BaseResponse<T>> {
//        return Observable<BaseResponse<T>>.create{ob in
//                //            let hud = MBProgressHUD.showAdded(to: screnDelegate!.window!, animated: true)
//                //            hud.bezelView.style = .solidColor
//                //            hud.contentColor = .white
//                //            hud.bezelView.backgroundColor = #colorLiteral(red: 0, green: 0, blue: 0, alpha: 0.8)
//                //            hud.bezelView.color = #colorLiteral(red: 0, green: 0, blue: 0, alpha: 0.8)
//                //            hud.removeFromSuperViewOnHide = true
//
//            var headers = HTTPHeaders()
//                //            if let token = UserViewModel.getUserInfo()?.token {
//                //                headers.add(name: "Authorization", value: "Bearer" + " " + token)
//                //                LogInfo("USER_token:\(token)")
//                //            }
//
//
//            AF.upload(multipartFormData: { data in
//                let p = params
//                LogInfo("Netrequest-Upload-Starting.")
//                for key in p.params{
//                    if let d = key.value as? Data {
//                        LogInfo("Netrequest-Upload-Appending-Data: Length = \(d.count) bytes")
//
//                        data.append(d, withName: key.key, fileName: "\(Date().timeIntervalSince1970).png", mimeType: "image/png")
//                    } else if let url = key.value as? URL {
//                        LogInfo("Netrequest-Upload-Appending-Data: Url = \(url)")
//                        data.append(url, withName: key.key)
//                    }
//                }
//            }, to: params.url, method: .post, headers: headers) .uploadProgress(queue: .main, closure: { progress in
//                    //                progressClosure(progress.fractionCompleted)
//            }).responseJSON(completionHandler: { data in
//                print("upload finished: \(data)")
//
//            }).response { (response) in
//
//                    //                hud.hide(animated: true)
//                switch response.result {
//                    case .success(let dataObj):
//                            //                    alert(msg: "上传成功")
//                        let jsonString = String(data: dataObj ?? Data(), encoding: String.Encoding.utf8)
//                        if let next = BaseResponse<T>.deserialize(from: jsonString){
//                            ob.onNext(next)
//                        }
//                    case .failure(let err):
//                        alert(msg: "上传失败")
//                        print("upload err: \(err)")
//                }
//
//            }
//            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))
}
WanPai/Network/Services.swift
New file
@@ -0,0 +1,164 @@
    //
    //  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.80:5209"
#else
let All_Url = "http://192.168.110.80:5209"
#endif
    // MARK: -- 首页部分
extension Services{
    class func homeInfo()->Observable<BaseResponse<HomeStoreModel>>{
        let params = ParamsAppender.build(url: All_Url)
            .interface(url: "/account/api/appUser/queryJoinPlayPai")
            .append(key: "lat", value: locationTool.currentLocation?.coordinate.latitude)
            .append(key: "lon", value: locationTool.currentLocation?.coordinate.longitude)
        return NetworkRequest.request(params: params, method: .post, progress: false)
    }
    class func homeStoreConfig(storeId:Int)->Observable<BaseResponse<[HomeStoreConfigModel]>>{
        let params = ParamsAppender.build(url: All_Url)
            .interface(url: "/other/base/store/queryStoreConfig")
            .append(key: "storeId", value: storeId)
        return NetworkRequest.request(params: params, method: .post, progress: false)
    }
}
    // MARK: -- 登录部分
class Services: NSObject {
    static let pageSize: Int = 20
    class func login(phone:String,verity:String,type:LoginType)->Observable<BaseResponse<String>>{
        let params = ParamsAppender.build(url: All_Url)
        if type == .pwd{
            params.interface(url: "/account/base/appUser/loginPassword")
            params.append(key: "password", value: verity.jq_md5String().uppercased())
        }else{
            params.interface(url: "/account/base/appUser/loginSMSCode")
            params.append(key: "code", value: verity)
        }
        params.append(key: "phone", value: phone)
        return NetworkRequest.request(params: params, method: .post, progress: true)
    }
    class func getSMSCode(phone:String,type:GetSMSCodeType)->Observable<BaseResponse<SimpleModel>>{
        let params = ParamsAppender.build(url: All_Url)
            .interface(url: "/account/base/appUser/getSMSCode")
            .append(key: "phone", value: phone)
            .append(key: "type", value: type.rawValue)
        return NetworkRequest.request(params: params, method: .post, progress: true)
    }
    class func register(phone:String,password:String,code:String)->Observable<BaseResponse<SimpleModel>>{
        let params = ParamsAppender.build(url: All_Url)
            .interface(url: "/account/base/appUser/addAppUser")
            .append(key: "phone", value: phone)
            .append(key: "password", value: password.jq_md5String().uppercased())
            .append(key: "code", value: code)
        return NetworkRequest.request(params: params, method: .post, progress: true)
    }
    class func updatePwd(phone:String,password:String,code:String)->Observable<BaseResponse<SimpleModel>>{
        let params = ParamsAppender.build(url: All_Url)
            .interface(url: "/account/base/appUser/updatePassword")
            .append(key: "phone", value: phone)
            .append(key: "password", value: password.jq_md5String().uppercased())
            .append(key: "code", value: code)
        return NetworkRequest.request(params: params, method: .post, progress: true)
    }
    class func forgetPwd(phone:String,password:String,code:String)->Observable<BaseResponse<SimpleModel>>{
        let params = ParamsAppender.build(url: All_Url)
            .interface(url: "/account/base/appUser/forgetPassword")
            .append(key: "phone", value: phone)
            .append(key: "password", value: password.jq_md5String().uppercased())
            .append(key: "code", value: code)
        return NetworkRequest.request(params: params, method: .post, progress: true)
    }
}
    // MARK: -- 课程相关
extension Services {
    class func queryCourseList(typeId:Int? = nil,distanceSort:SortType? = nil,salesRanking:SortType? = nil,search:String? = nil,storeId:Int? = nil)->Observable<BaseResponse<[CourseItemModel]>>{
        let params = ParamsAppender.build(url: All_Url)
            .interface(url: "/course/api/course/queryCourseList")
            .append(key: "lat", value: locationTool.currentLocation?.coordinate.latitude)
            .append(key: "lon", value: locationTool.currentLocation?.coordinate.longitude)
            .append(key: "coursePackageTypeId", value: typeId)
            .append(key: "distanceSort", value: distanceSort?.rawValue)
            .append(key: "salesRanking", value: salesRanking?.rawValue)
            .append(key: "search", value: search)
            .append(key: "storeId", value: storeId)
        return NetworkRequest.request(params: params, method: .post, progress: false)
    }
    class func coursePackageType()->Observable<BaseResponse<[NormalSimpleModel]>>{
        let params = ParamsAppender.build(url: All_Url)
            .interface(url: "/course/api/course/queryCoursePackageType")
        return NetworkRequest.request(params: params, method: .post, progress: false)
    }
    class func queryStoreList()->Observable<BaseResponse<[NormalSimpleModel]>>{
        let params = ParamsAppender.build(url: All_Url)
            .interface(url: "/other/base/store/queryStoreLists")
            .append(key: "lat", value: locationTool.currentLocation?.coordinate.latitude)
            .append(key: "lon", value: locationTool.currentLocation?.coordinate.longitude)
        return NetworkRequest.request(params: params, method: .post, progress: false)
    }
    class func queryCourseInfo(id:Int)->Observable<BaseResponse<CourseDetailModel>>{
        let params = ParamsAppender.build(url: All_Url)
            .interface(url: "/course/api/course/queryCourseInfo")
            .append(key: "id", value: id)
            .append(key: "lat", value: locationTool.currentLocation?.coordinate.latitude)
            .append(key: "lon", value: locationTool.currentLocation?.coordinate.longitude)
        return NetworkRequest.request(params: params, method: .post, progress: true)
    }
}
    // MARK: -- 其他
extension Services{
    class func queryProtocol(_ type:AgreentType,progress:Bool = true)->Observable<BaseResponse<String>>{
        let params = ParamsAppender.build(url: All_Url)
            .interface(url: "/other/base/protocol/queryProtocol")
            .append(key: "type", value: type.rawValue)
        return NetworkRequest.request(params: params, method: .post, progress: progress)
    }
    class func querySystemImg(type:SystemImgType)->Observable<BaseResponse<String>>{
        let params = ParamsAppender.build(url: All_Url)
            .interface(url: "/other/base/systemImg/querySystemImg")
            .append(key: "position", value: type.rawValue)
        return NetworkRequest.request(params: params, method: .post, progress: false)
    }
}
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
            }
        })
    }
}
WanPai/Root/Activity/VC/ActivityListVC.swift
@@ -53,7 +53,8 @@
    @IBAction func signupConditionAction(_ sender: QMUIButton) {
        guard !sender.isSelected else {return}
        sender.isSelected = true
        CourseSubTypeView.show(inView: self.view, afterView: btn_joinCondition, items: ["全部用户参与","仅限年度会员参与","仅限学员参与"]) { str in
        let items = Array<NormalSimpleModel>()
        CourseSubTypeView.show(inView: self.view, afterView: btn_joinCondition, items: items) { m in
            sender.isSelected = false
            
        } closeClouse: {
WanPai/Root/Course/TCell/CourseTCell.swift
@@ -6,8 +6,42 @@
//
import UIKit
import SDWebImage
import JQTools
class CourseTCell: UITableViewCell {
    @IBOutlet weak var img_cover: UIImageView!
    @IBOutlet weak var label_title: UILabel!
    @IBOutlet weak var label_teachTime: UILabel!
    @IBOutlet weak var label_enrollNumber: UILabel!
    @IBOutlet weak var label_vipPrice: UILabel!
    @IBOutlet weak var label_price: UILabel!
    @IBOutlet weak var label_distance: UILabel!
    @IBOutlet weak var label_originPrice: UILabel!
    @IBOutlet weak var stackView_vipPrice: UIStackView!
    var courseItemModel:CourseItemModel!{
        didSet{
            stackView_vipPrice.isHidden = courseItemModel.originalPrice == nil
            label_originPrice.isHidden = courseItemModel.originalPrice == nil
            img_cover.sd_setImage(with: URL(string: courseItemModel.coverDrawing))
            label_title.text = String(format: "%@(%@)", courseItemModel.name,courseItemModel.storeName)
            label_teachTime.text = String(format: "上课时间:%@", courseItemModel.classStartTime)
            label_enrollNumber.text = String(format: "已报名:%ld人", courseItemModel.applicantsNumber)
            label_distance.text = String(format: "%.2lfkm", courseItemModel.distance)
            if courseItemModel.payType == .cash{
                label_price.text = courseItemModel.paymentPrice.currency()
            }else if courseItemModel.payType == .coin{
                label_price.text = "玩湃币 " + "\(courseItemModel.playPaiCoin)"
            }
            label_originPrice.attributedText = AttributedStringbuilder.build().add(string: courseItemModel.originalPrice?.currency() ?? "", withFont: UIFont.systemFont(ofSize: 14, weight: .semibold), withColor: UIColor(hexStr: "#C6C6C6")).underLine(color: UIColor(hexStr: "#C6C6C6")).mutableAttributedString
        }
    }
    override func awakeFromNib() {
        super.awakeFromNib()
WanPai/Root/Course/TCell/CourseTCell.xib
@@ -1,9 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="21507" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="21701" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
    <device id="retina6_12" orientation="portrait" appearance="light"/>
    <dependencies>
        <deployment identifier="iOS"/>
        <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="21505"/>
        <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="21679"/>
        <capability name="Named colors" minToolsVersion="9.0"/>
        <capability name="Safe area layout guides" minToolsVersion="9.0"/>
        <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
@@ -11,16 +11,17 @@
    <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="_CourseTCell" rowHeight="201" id="KGk-i7-Jjw" customClass="CourseTCell" customModule="WanPai" customModuleProvider="target">
            <rect key="frame" x="0.0" y="0.0" width="445" height="201"/>
        <tableViewCell contentMode="scaleToFill" selectionStyle="default" indentationWidth="10" reuseIdentifier="_CourseTCell" rowHeight="188" id="KGk-i7-Jjw" customClass="CourseTCell" customModule="WanPai" customModuleProvider="target">
            <rect key="frame" x="0.0" y="0.0" width="445" height="188"/>
            <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="0.0" width="445" height="201"/>
                <rect key="frame" x="0.0" y="0.0" width="445" height="188"/>
                <autoresizingMask key="autoresizingMask"/>
                <subviews>
                    <imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="placeholder_1" translatesAutoresizingMaskIntoConstraints="NO" id="kG4-xU-j01">
                        <rect key="frame" x="14.000000000000007" y="21" width="118.66666666666669" height="158"/>
                    <imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="placeholder_1" translatesAutoresizingMaskIntoConstraints="NO" id="kG4-xU-j01">
                        <rect key="frame" x="14" y="21" width="106" height="141"/>
                        <constraints>
                            <constraint firstAttribute="width" constant="105" id="ZM8-kR-jRq"/>
                            <constraint firstAttribute="width" secondItem="kG4-xU-j01" secondAttribute="height" multiplier="1:1.33" id="kZu-F8-aRD"/>
                        </constraints>
                        <userDefinedRuntimeAttributes>
@@ -30,7 +31,7 @@
                        </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="KYY-Ie-Ipd">
                        <rect key="frame" x="142.66666666666666" y="20" width="292.33333333333337" height="22"/>
                        <rect key="frame" x="130" y="20" width="305" height="22"/>
                        <constraints>
                            <constraint firstAttribute="height" constant="22" id="09U-HJ-nDG"/>
                        </constraints>
@@ -39,7 +40,7 @@
                        <nil key="highlightedColor"/>
                    </label>
                    <stackView opaque="NO" contentMode="scaleToFill" axis="vertical" spacing="9" translatesAutoresizingMaskIntoConstraints="NO" id="eNH-LC-iLJ">
                        <rect key="frame" x="143.66666666666666" y="51" width="90.666666666666657" height="78"/>
                        <rect key="frame" x="131" y="51" width="90.666666666666686" height="78"/>
                        <subviews>
                            <stackView opaque="NO" contentMode="scaleToFill" spacing="3" translatesAutoresizingMaskIntoConstraints="NO" id="Av5-eD-vOm">
                                <rect key="frame" x="0.0" y="0.0" width="90.666666666666671" height="20"/>
@@ -101,14 +102,14 @@
                        </subviews>
                    </stackView>
                    <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="tOW-TH-1JZ">
                        <rect key="frame" x="13" y="200.66666666666666" width="419" height="0.33333333333334281"/>
                        <rect key="frame" x="13" y="183.66666666666666" width="419" height="0.33333333333334281"/>
                        <color key="backgroundColor" red="0.59215686274509804" green="0.59215686274509804" blue="0.59215686274509804" alpha="0.22" colorSpace="custom" customColorSpace="sRGB"/>
                        <constraints>
                            <constraint firstAttribute="height" constant="0.5" id="UqP-R7-dtT"/>
                        </constraints>
                    </view>
                    <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="¥ 0" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="cfM-fa-irQ">
                        <rect key="frame" x="142.66666666666666" y="155" width="27.666666666666657" height="25"/>
                        <rect key="frame" x="130" y="138" width="27.666666666666657" height="25"/>
                        <constraints>
                            <constraint firstAttribute="height" constant="25" id="xWn-hk-QRE"/>
                        </constraints>
@@ -117,13 +118,13 @@
                        <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="46M-8z-ObJ">
                        <rect key="frame" x="177.33333333333334" y="159" width="22" height="17"/>
                        <rect key="frame" x="164.66666666666666" y="142" width="22" height="17"/>
                        <fontDescription key="fontDescription" type="system" weight="semibold" pointSize="14"/>
                        <color key="textColor" red="0.77647058823529413" green="0.77647058823529413" blue="0.77647058823529413" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
                        <nil key="highlightedColor"/>
                    </label>
                    <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="qZP-3L-42h">
                        <rect key="frame" x="366" y="144.66666666666666" width="65" height="31"/>
                    <button opaque="NO" userInteractionEnabled="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="qZP-3L-42h">
                        <rect key="frame" x="366" y="127.66666666666669" width="65" height="31"/>
                        <color key="backgroundColor" name="FE6E0D"/>
                        <constraints>
                            <constraint firstAttribute="height" constant="31" id="QJh-lv-KCw"/>
@@ -140,7 +141,7 @@
                        </userDefinedRuntimeAttributes>
                    </button>
                    <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="0km" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="ZKZ-AF-Nb9">
                        <rect key="frame" x="398" y="98.333333333333329" width="33" height="19.333333333333329"/>
                        <rect key="frame" x="398" y="81.333333333333329" width="33" height="19.333333333333329"/>
                        <fontDescription key="fontDescription" type="system" weight="medium" pointSize="16"/>
                        <color key="textColor" red="0.23921568627450979" green="0.24313725490196078" blue="0.27058823529411763" alpha="0.68999999999999995" colorSpace="custom" customColorSpace="sRGB"/>
                        <nil key="highlightedColor"/>
@@ -169,7 +170,18 @@
                </constraints>
            </tableViewCellContentView>
            <viewLayoutGuide key="safeArea" id="njF-e1-oar"/>
            <point key="canvasLocation" x="135.1145038167939" y="75"/>
            <connections>
                <outlet property="img_cover" destination="kG4-xU-j01" id="v3X-Cw-SeR"/>
                <outlet property="label_distance" destination="ZKZ-AF-Nb9" id="OTQ-xB-tXm"/>
                <outlet property="label_enrollNumber" destination="s8o-AB-aTs" id="whR-hE-bZp"/>
                <outlet property="label_originPrice" destination="46M-8z-ObJ" id="95c-PR-Xqr"/>
                <outlet property="label_price" destination="cfM-fa-irQ" id="2ws-4x-hJe"/>
                <outlet property="label_teachTime" destination="vOz-k7-E1C" id="ZVK-CO-Jhn"/>
                <outlet property="label_title" destination="KYY-Ie-Ipd" id="qAH-3T-KMM"/>
                <outlet property="label_vipPrice" destination="iGs-ae-BBu" id="VqQ-kR-kqc"/>
                <outlet property="stackView_vipPrice" destination="4j1-WG-XCo" id="5zG-bq-8lX"/>
            </connections>
            <point key="canvasLocation" x="135.1145038167939" y="64.08450704225352"/>
        </tableViewCell>
    </objects>
    <resources>
@@ -178,7 +190,7 @@
        <image name="icon_vip" width="12" height="12"/>
        <image name="placeholder_1" width="106" height="141"/>
        <namedColor name="FE6E0D">
            <color red="0.99599999189376831" green="0.4309999942779541" blue="0.050999999046325684" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
            <color red="0.99199998378753662" green="0.53299999237060547" blue="0.0080000003799796104" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
        </namedColor>
    </resources>
</document>
WanPai/Root/Course/VC/CourseDetailVC.swift
@@ -7,13 +7,94 @@
import UIKit
import QMUIKit
import JQTools
class CourseDetailVC: BaseVC {
    @IBOutlet weak var img_cover: UIImageView!
    @IBOutlet weak var label_title: UILabel!
    @IBOutlet weak var btn_local: QMUIButton!
    @IBOutlet weak var label_distance: UILabel!
    @IBOutlet weak var label_listenWeek: UILabel!
    @IBOutlet weak var label_listenTime: UILabel!
    @IBOutlet weak var img_1: UIImageView!
    @IBOutlet weak var img_2: UIImageView!
    @IBOutlet weak var cons_img1Height: NSLayoutConstraint!
    @IBOutlet weak var cons_img2Height: NSLayoutConstraint!
    @IBOutlet weak var label_price: UILabel!
    @IBOutlet weak var label_originPrice: UILabel!
    @IBOutlet weak var label_vipPrice: UILabel!
    @IBOutlet weak var label_coin: UILabel!
    private var id = 0
    private var detailModel:CourseDetailModel!{
        didSet{
            img_cover.sd_setImage(with: URL(string: detailModel.coverDrawing))
            label_title.text = detailModel.name
            label_distance.text = String(format: "距离我%.2lfkm", detailModel.distance)
            btn_local.setTitle(detailModel.storeAddress, for: .normal)
            label_listenWeek.text = detailModel.weeks.joined(separator: "、")
            label_listenTime.text = detailModel.times
            img_1.sd_setImage(with: URL(string: detailModel.introduceDrawing)) { image, error, type, url in
                let radio = image!.size.width / image!.size.height
                self.cons_img1Height.constant = JQ_ScreenH * radio
            }
            img_2.sd_setImage(with: URL(string: detailModel.detailDrawing)) { image, error, type, url in
                let radio = image!.size.width / image!.size.height
                self.cons_img2Height.constant = JQ_ScreenH * radio
            }
            label_price.text = detailModel.list.first!.paymentPrice.currency()
            if let subM = detailModel.list.first {
                label_originPrice.isHidden = subM.originalPrice == 0
                label_coin.isHidden = subM.playPaiCoin == 0
                label_vipPrice.isHidden = subM.vipPrice == 0
                //原价
                let attribute = AttributedStringbuilder.build().add(string: subM.originalPrice.currency(), withFont: UIFont.systemFont(ofSize: 16, weight: .semibold), withColor: UIColor(hexStr: "#3F3F3F").withAlphaComponent(0.58)).underLine(color: UIColor(hexStr: "#3F3F3F").withAlphaComponent(0.58))
                label_originPrice.attributedText = attribute.mutableAttributedString
                //玩湃币
                let coinAttribute = AttributedStringbuilder.build()
                    .add(string: "玩湃币:", withFont: UIFont.systemFont(ofSize: 14, weight: .semibold), withColor: UIColor(hexStr: "#3F3F3F"))
                    .add(string: "\(subM.playPaiCoin)币", withFont: UIFont.systemFont(ofSize: 14, weight: .semibold), withColor: UIColor(hexStr: "#F21313"))
                label_coin.attributedText = coinAttribute.mutableAttributedString
                //会员价
                let vipAttribute = AttributedStringbuilder.build()
                    .add(string: "会员价:", withFont: UIFont.systemFont(ofSize: 14, weight: .semibold), withColor: UIColor(hexStr: "#3F3F3F"))
                    .add(string: subM.vipPrice.currency(), withFont: UIFont.systemFont(ofSize: 14, weight: .semibold), withColor: UIColor(hexStr: "#F21313"))
                label_vipPrice.attributedText = vipAttribute.mutableAttributedString
            }
        }
    }
    required init(id:Int) {
        super.init(nibName: nil, bundle: nil)
        self.id = id
    }
    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    override func viewDidLoad() {
        super.viewDidLoad()
        title = "课程详情"
        Services.queryCourseInfo(id: id).subscribe(onNext: { data in
            if let m = data.data{
                self.detailModel = m
            }
        }).disposed(by: disposeBag)
    }
    
    override func setUI() {
@@ -28,7 +109,6 @@
    
    
    @IBAction func localAction(_ sender: QMUIButton) {
        JQ_MapNavigationTool.startNav(CLLocationCoordinate2D(latitude: detailModel.lat.toDouble, longitude: detailModel.lon.toDouble), distanceName: detailModel.storeAddress, scheme: "weparklife")
    }
}
WanPai/Root/Course/VC/CourseDetailVC.xib
@@ -1,9 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="21507" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="21701" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
    <device id="retina6_12" orientation="portrait" appearance="light"/>
    <dependencies>
        <deployment identifier="iOS"/>
        <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="21505"/>
        <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="21679"/>
        <capability name="Named colors" minToolsVersion="9.0"/>
        <capability name="Safe area layout guides" minToolsVersion="9.0"/>
        <capability name="System colors in document resources" minToolsVersion="11.0"/>
@@ -13,6 +13,19 @@
        <placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner" customClass="CourseDetailVC" customModule="WanPai" customModuleProvider="target">
            <connections>
                <outlet property="btn_local" destination="ejk-Ik-4lo" id="Gds-GI-U25"/>
                <outlet property="cons_img1Height" destination="ra0-2L-YY8" id="zQn-ar-ffC"/>
                <outlet property="cons_img2Height" destination="xwL-l2-kBa" id="qmV-Wg-NqV"/>
                <outlet property="img_1" destination="OTP-xt-gbB" id="ndO-dv-UDx"/>
                <outlet property="img_2" destination="UC8-uA-Izr" id="JBD-Yf-pWV"/>
                <outlet property="img_cover" destination="Z8w-gF-Zqx" id="8kq-hZ-b27"/>
                <outlet property="label_coin" destination="ldz-Xc-RZY" id="jPO-eU-nzM"/>
                <outlet property="label_distance" destination="IzD-lg-sfB" id="NyX-OW-yyz"/>
                <outlet property="label_listenTime" destination="6RN-lP-9js" id="PLB-BZ-cHI"/>
                <outlet property="label_listenWeek" destination="utV-MS-Xge" id="gVe-Sf-Ag9"/>
                <outlet property="label_originPrice" destination="pXk-ET-NAX" id="E4r-vs-9I7"/>
                <outlet property="label_price" destination="moa-lg-TqA" id="6OB-8j-Jl7"/>
                <outlet property="label_title" destination="AU1-6y-12Y" id="QBG-zt-Fqe"/>
                <outlet property="label_vipPrice" destination="Dqe-kc-hu1" id="eWc-K6-43L"/>
                <outlet property="view" destination="i5M-Pr-FkT" id="sfx-zR-JGt"/>
            </connections>
        </placeholder>
@@ -62,7 +75,7 @@
                                            <nil key="textColor"/>
                                            <nil key="highlightedColor"/>
                                        </label>
                                        <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="leading" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="ejk-Ik-4lo" customClass="QMUIButton">
                                        <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="ejk-Ik-4lo" customClass="QMUIButton">
                                            <rect key="frame" x="14" y="46" width="223" height="18"/>
                                            <constraints>
                                                <constraint firstAttribute="height" constant="18" id="hIU-Ca-ItQ"/>
@@ -180,16 +193,22 @@
                            <nil key="highlightedColor"/>
                        </label>
                        <stackView opaque="NO" contentMode="scaleToFill" axis="vertical" spacing="2" translatesAutoresizingMaskIntoConstraints="NO" id="AaO-wm-Phu">
                            <rect key="frame" x="52.666666666666657" y="19.666666666666629" width="57.333333333333343" height="36"/>
                            <rect key="frame" x="52.666666666666657" y="10" width="57.333333333333343" height="55"/>
                            <subviews>
                                <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="会员价:" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="pXk-ET-NAX">
                                <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="原价" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="pXk-ET-NAX">
                                    <rect key="frame" x="0.0" y="0.0" width="57.333333333333336" height="17"/>
                                    <fontDescription key="fontDescription" type="system" weight="semibold" pointSize="14"/>
                                    <color key="textColor" red="0.24705882352941178" green="0.24705882352941178" blue="0.24705882352941178" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
                                    <nil key="highlightedColor"/>
                                </label>
                                <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="玩湃币:" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="ldz-Xc-RZY">
                                <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="会员价:" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Dqe-kc-hu1">
                                    <rect key="frame" x="0.0" y="19" width="57.333333333333336" height="17"/>
                                    <fontDescription key="fontDescription" type="system" weight="semibold" pointSize="14"/>
                                    <color key="textColor" red="0.2470588235" green="0.2470588235" blue="0.2470588235" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
                                    <nil key="highlightedColor"/>
                                </label>
                                <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="玩湃币:" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="ldz-Xc-RZY">
                                    <rect key="frame" x="0.0" y="38" width="57.333333333333336" height="17"/>
                                    <fontDescription key="fontDescription" type="system" weight="semibold" pointSize="14"/>
                                    <color key="textColor" red="0.2470588235" green="0.2470588235" blue="0.2470588235" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
                                    <nil key="highlightedColor"/>
@@ -256,7 +275,7 @@
    <resources>
        <image name="icon_local_mini" width="11" height="16"/>
        <namedColor name="FE6E0D">
            <color red="0.99599999189376831" green="0.4309999942779541" blue="0.050999999046325684" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
            <color red="0.99199998378753662" green="0.53299999237060547" blue="0.0080000003799796104" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
        </namedColor>
        <systemColor name="systemBackgroundColor">
            <color white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
WanPai/Root/Course/VC/CourseExerciseSubListVC.swift
@@ -32,7 +32,8 @@
    @IBAction func assignAction(_ sender: QMUIButton) {
        guard !sender.isSelected else {return}
        sender.isSelected = true
        CourseSubTypeView.show(inView: self.view, afterView: view_topView, items: ["足球课程","篮球课程","羽毛球课程","网球课程"]) { str in
        let items = Array<NormalSimpleModel>()
        CourseSubTypeView.show(inView: self.view, afterView: view_topView, items: items) { m in
            sender.isSelected = false
        } closeClouse: {
WanPai/Root/Course/VC/CourseListVC.swift
@@ -7,20 +7,62 @@
import UIKit
import QMUIKit
import JQTools
import RxSwift
import RxDataSources
import RxCocoa
class CourseListVC: BaseVC {
class CourseListViewModel{
    var disposeBag = DisposeBag()
    var packageTypeData = BehaviorRelay<[NormalSimpleModel]?>(value: nil)
    var storesData = BehaviorRelay<[NormalSimpleModel]?>(value: nil)
    var selectPackeType = BehaviorRelay<NormalSimpleModel?>(value: nil)
    var selectStore = BehaviorRelay<NormalSimpleModel?>(value: nil)
    var distanceSort = BehaviorRelay<SortType?>(value: nil)
    var salesRanking = BehaviorRelay<SortType?>(value: nil)
    var search = BehaviorRelay<String?>(value: nil)
    func getDefaultData(){
        Services.coursePackageType().subscribe(onNext: {[weak self] data in
            if var datas = data.data{
                datas.insert(NormalSimpleModel(id: -1, name: "全部"), at: 0)
                self?.packageTypeData.accept(datas)
            }
        }) { error in
        }.disposed(by: disposeBag)
        Services.queryStoreList().subscribe(onNext: {[weak self] data in
            if var datas = data.data{
                datas.insert(NormalSimpleModel(id: -1, name: "全部"), at: 0)
                self?.storesData.accept(datas)
            }
        }) { error in
        }.disposed(by: disposeBag)
    }
}
class CourseListVC: BaseVC,Refreshable{
    @IBOutlet weak var view_topView: UIView!
    @IBOutlet weak var tf_search: QMUITextField!
    @IBOutlet weak var tableView: UITableView!
    @IBOutlet weak var tableView: BaseTableView!
    @IBOutlet weak var btn_courseType: QMUIButton!
    @IBOutlet weak var btn_stores: QMUIButton!
    @IBOutlet weak var btn_sales: QMUIButton!
    @IBOutlet weak var btn_distance: QMUIButton!
    var items = [CourseItemModel]()
    private var viewModel = CourseListViewModel()
    private var showSubTypeView:CourseSubTypeView?
    
    override func viewDidLoad() {
        super.viewDidLoad()
        title = "课程列表"
        viewModel.getDefaultData()
    }
    
    override func setUI() {
@@ -38,6 +80,43 @@
        tableView.dataSource = self
        tableView.register(UINib(nibName: "CourseTCell", bundle: nil), forCellReuseIdentifier: "_CourseTCell")
        tableView.separatorStyle = .none
        tf_search.delegate = self
        tableView.jq_setEmptyView()
        refreshStatusBind(to: tableView) {[weak self] in
            self?.getData()
        } footer: {}
        refreshStatus.onNext(.beingHeaderRefresh)
    }
    override func setRx() {
        tf_search.rx.controlEvent(.editingDidEnd).subscribe(onNext: { [weak self] in
            if self?.tf_search.text?.isEmpty ?? true{
                self?.viewModel.search.accept(nil)
            }else{
                self?.viewModel.search.accept(self?.tf_search.text!)
            }
        }).disposed(by: disposeBag)
    }
    private func getData(_ header:Bool = true){
        Services.queryCourseList(typeId: viewModel.selectPackeType.value?.id, distanceSort: viewModel.distanceSort.value, salesRanking: viewModel.salesRanking.value, search: viewModel.search.value, storeId: viewModel.selectStore.value?.id).subscribe { [weak self] data in
            self?.refreshStatus.onNext(.endAll)
            self?.items = data.data ?? []
            self?.tableView.reloadData()
        } onError: {[weak self] error in
            self?.refreshStatus.onNext(.endAll)
        }.disposed(by: disposeBag)
    }
    private func cleanOther(){
        showSubTypeView?.removeFromSuperview()
        btn_courseType.isSelected = false
        btn_stores.isSelected = false
        btn_sales.isSelected = false
        btn_distance.isSelected = false
    }
    
    @IBAction func searchAction(_ sender: UIButton) {
@@ -45,40 +124,77 @@
    }
    
    @IBAction func crouseTypeAction(_ sender: UIButton) {
        guard viewModel.packageTypeData.value != nil else {
            alertError(msg: "分类数据加载失败,请再试一次")
            viewModel.getDefaultData()
            return
        }
        guard !sender.isSelected else {return}
        cleanOther()
        sender.isSelected = true
        CourseSubTypeView.show(inView: self.view, afterView: view_topView, items: ["足球课程","篮球课程","羽毛球课程","网球课程"]) { str in
        showSubTypeView = CourseSubTypeView.show(inView: self.view, afterView: view_topView, items: viewModel.packageTypeData.value!,selectModel: viewModel.selectPackeType.value) { [weak self] m in
            if m.name != "全部"{
                sender.setTitle(m.name, for: .normal)
                self?.viewModel.selectPackeType.accept(m)
            }else{
                sender.setTitle("课程类型", for: .normal)
                self?.viewModel.selectPackeType.accept(nil)
            }
            sender.isSelected = false
            self?.refreshStatus.onNext(.beingHeaderRefresh)
        } closeClouse: {
            sender.isSelected = false
        }
    }
    
    @IBAction func inStoresAction(_ sender: UIButton) {
        guard viewModel.storesData.value != nil else {
            alertError(msg: "分类数据加载失败,请再试一次")
            viewModel.getDefaultData()
            return
        }
        guard !sender.isSelected else {return}
        cleanOther()
        sender.isSelected = true
        CourseSubTypeView.show(inView: self.view, afterView: view_topView, items: ["玩湃-喜望店","玩湃-喜望店","玩湃-喜望店","玩湃-喜望店"]) { str in
        showSubTypeView =  CourseSubTypeView.show(inView: self.view, afterView: view_topView, items: viewModel.storesData.value!,selectModel: viewModel.selectStore.value) { [weak self] m in
            if m.name != "全部"{
                sender.setTitle(m.name, for: .normal)
                self?.viewModel.selectStore.accept(m)
            }else{
                sender.setTitle("所在门店", for: .normal)
                self?.viewModel.selectStore.accept(nil)
            }
            sender.isSelected = false
            self?.refreshStatus.onNext(.beingHeaderRefresh)
        } closeClouse: {
            sender.isSelected = false
        }
    }
    
    @IBAction func saleAction(_ sender: UIButton) {
        sender.isSelected = !sender.isSelected
        let sortType = sender.isSelected ? SortType.desc:SortType.asc
        viewModel.salesRanking.accept(sortType)
        sender.setImage(viewModel.salesRanking.value?.img, for: .normal)
        refreshStatus.onNext(.beingHeaderRefresh)
    }
    
    @IBAction func distanceAction(_ sender: UIButton) {
        sender.isSelected = !sender.isSelected
        let sortType = sender.isSelected ? SortType.desc:SortType.asc
        viewModel.distanceSort.accept(sortType)
        sender.setImage(viewModel.distanceSort.value?.img, for: .normal)
        refreshStatus.onNext(.beingHeaderRefresh)
    }
    
}
extension CourseListVC:UITableViewDelegate{
    func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        let vc = CourseDetailVC()
        let item = items[indexPath.row]
        let vc = CourseDetailVC(id: item.id)
        push(vc: vc)
    }
    
@@ -87,12 +203,19 @@
extension CourseListVC:UITableViewDataSource{
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
         let cell = tableView.dequeueReusableCell(withIdentifier: "_CourseTCell") as! CourseTCell
        cell.courseItemModel = items[indexPath.row]
        return cell
    }
    
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return 5
        return items.count
    }
}
extension CourseListVC:QMUITextFieldDelegate{
    func textFieldShouldReturn(_ textField: UITextField) -> Bool {
        textField.resignFirstResponder()
        refreshStatus.onNext(.beingHeaderRefresh)
        return true
    }
}
WanPai/Root/Course/VC/CourseListVC.xib
@@ -1,9 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="21507" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="21701" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
    <device id="retina6_12" orientation="portrait" appearance="light"/>
    <dependencies>
        <deployment identifier="iOS"/>
        <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="21505"/>
        <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="21679"/>
        <capability name="Named colors" minToolsVersion="9.0"/>
        <capability name="Safe area layout guides" minToolsVersion="9.0"/>
        <capability name="System colors in document resources" minToolsVersion="11.0"/>
@@ -109,10 +109,9 @@
                                    <rect key="frame" x="220.66666666666666" y="0.0" width="59.999999999999972" height="52"/>
                                    <fontDescription key="fontDescription" type="system" weight="medium" pointSize="16"/>
                                    <inset key="imageEdgeInsets" minX="0.0" minY="0.0" maxX="2.2250738585072014e-308" maxY="0.0"/>
                                    <state key="normal" title="销量" image="icon_aes">
                                    <state key="normal" title="销量" image="icon_sort_normal">
                                        <color key="titleColor" white="0.0" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
                                    </state>
                                    <state key="selected" image="icon_des"/>
                                    <state key="highlighted" image="icon_sort_normal"/>
                                    <connections>
                                        <action selector="saleAction:" destination="-1" eventType="touchUpInside" id="3qT-GH-pha"/>
@@ -122,10 +121,9 @@
                                    <rect key="frame" x="305" y="0.0" width="60" height="52"/>
                                    <fontDescription key="fontDescription" type="system" weight="medium" pointSize="16"/>
                                    <inset key="imageEdgeInsets" minX="0.0" minY="0.0" maxX="2.2250738585072014e-308" maxY="0.0"/>
                                    <state key="normal" title="距离" image="icon_aes">
                                    <state key="normal" title="距离" image="icon_sort_normal">
                                        <color key="titleColor" white="0.0" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
                                    </state>
                                    <state key="selected" image="icon_des"/>
                                    <state key="highlighted" image="icon_sort_normal"/>
                                    <connections>
                                        <action selector="distanceAction:" destination="-1" eventType="touchUpInside" id="6di-mn-nZf"/>
@@ -161,7 +159,7 @@
                        </userDefinedRuntimeAttribute>
                    </userDefinedRuntimeAttributes>
                </view>
                <tableView clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" style="plain" separatorStyle="default" rowHeight="-1" estimatedRowHeight="-1" sectionHeaderHeight="-1" estimatedSectionHeaderHeight="-1" sectionFooterHeight="-1" estimatedSectionFooterHeight="-1" translatesAutoresizingMaskIntoConstraints="NO" id="Uy7-FM-GEG">
                <tableView clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" style="plain" separatorStyle="default" rowHeight="-1" estimatedRowHeight="-1" sectionHeaderHeight="-1" estimatedSectionHeaderHeight="-1" sectionFooterHeight="-1" estimatedSectionFooterHeight="-1" translatesAutoresizingMaskIntoConstraints="NO" id="Uy7-FM-GEG" customClass="BaseTableView" customModule="WanPai" customModuleProvider="target">
                    <rect key="frame" x="0.0" y="169" width="393" height="649"/>
                    <color key="backgroundColor" systemColor="systemBackgroundColor"/>
                </tableView>
@@ -181,14 +179,12 @@
        </view>
    </objects>
    <resources>
        <image name="icon_aes" width="27" height="30"/>
        <image name="icon_des" width="27" height="30"/>
        <image name="icon_down_arrow" width="20" height="14"/>
        <image name="icon_down_arrow_s" width="20" height="14"/>
        <image name="icon_search" width="17" height="17"/>
        <image name="icon_sort_normal" width="27" height="30"/>
        <namedColor name="FE6E0D">
            <color red="0.99599999189376831" green="0.4309999942779541" blue="0.050999999046325684" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
            <color red="0.99199998378753662" green="0.53299999237060547" blue="0.0080000003799796104" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
        </namedColor>
        <systemColor name="systemBackgroundColor">
            <color white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
WanPai/Root/Course/VC/CourseVideoDetailVC.swift
@@ -6,12 +6,35 @@
//
import UIKit
import MediaPlayer
import AVKit
class CourseVideoDetailVC: BaseVC {
    @IBOutlet weak var view_videoContainer: UIView!
    private lazy var playerVC:AVPlayerViewController = {
        let player = AVPlayerViewController()
        player.allowsPictureInPicturePlayback = true
        player.delegate = self
        return player
    }()
    override func viewDidLoad() {
        super.viewDidLoad()
        playerVC.player = AVPlayer(url: URL(string: "https://media.w3.org/2010/05/sintel/trailer.mp4")!)
        playerVC.player?.play()
    }
    override func setUI() {
        view_videoContainer.addSubview(playerVC.view)
        playerVC.view.frame = view_videoContainer.frame
        self.addChild(playerVC)
        playerVC.didMove(toParent: self)
    }
}
extension CourseVideoDetailVC:AVPlayerViewControllerDelegate{
}
WanPai/Root/Course/VC/CourseVideoDetailVC.xib
@@ -12,6 +12,7 @@
        <placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner" customClass="CourseVideoDetailVC" customModule="WanPai" customModuleProvider="target">
            <connections>
                <outlet property="view" destination="i5M-Pr-FkT" id="sfx-zR-JGt"/>
                <outlet property="view_videoContainer" destination="iUz-vy-vlj" id="bef-n3-npl"/>
            </connections>
        </placeholder>
        <placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
WanPai/Root/Course/VC/StudentCourseDetailVC.swift
@@ -91,7 +91,7 @@
        btn.titleLabel?.font = UIFont.systemFont(ofSize: 16)
        btn.jq_borderWidth = 1
        btn.jq_borderColor = UIColor(hexStr: "#D5D1D1")
        btn.cornerRadius = 4
        btn.jq_cornerRadius = 4
        btn.setTitle("全部记录", for: .normal)
        btn.setImage(UIImage(named: "icon_down_arrow"), for: .normal)
        btn.imagePosition = .right
WanPai/Root/Course/View/CourseSubTypeView.swift
@@ -13,23 +13,28 @@
    @IBOutlet weak var tableView: UITableView!
    @IBOutlet weak var cons_tableHeight: NSLayoutConstraint!
    private var closeClouse:(()->Void)?
    private var clouse:((String)->Void)?
    private var clouse:((NormalSimpleModel)->Void)?
    private var items = [NormalSimpleModel]()
    private var selectModel:NormalSimpleModel?
    
    override func awakeFromNib() {
        super.awakeFromNib()
        
        tableView.delegate = self
        tableView.dataSource = self
        tableView.separatorStyle = .none
        tableView.register(UINib(nibName: "Common_1_TCell", bundle: nil), forCellReuseIdentifier: "_Common_1_TCell")
        alpha = 0
        cons_tableHeight.constant = 0
        layoutIfNeeded()
    }
    
    static func show(inView:UIView,afterView:UIView,items:[String],clouse:@escaping (String)->Void,closeClouse:@escaping ()->Void){
    static func show(inView:UIView,afterView:UIView,items:[NormalSimpleModel],selectModel:NormalSimpleModel? = nil,clouse:@escaping (NormalSimpleModel)->Void,closeClouse:@escaping ()->Void)->CourseSubTypeView{
        let subTypeView = CourseSubTypeView.jq_loadNibView()
        subTypeView.closeClouse = closeClouse
        subTypeView.clouse = clouse
        subTypeView.items = items
        subTypeView.selectModel = selectModel
        inView.addSubview(subTypeView)
        subTypeView.snp.makeConstraints { make in
            make.top.equalTo(afterView.snp.bottom)
@@ -39,11 +44,14 @@
        UIView.animate(withDuration: 0.2) {
            subTypeView.alpha = 1
        } completion: { _ in
            subTypeView.cons_tableHeight.constant = 220
            subTypeView.cons_tableHeight.constant = CGFloat(min(items.count * 50, 250))
            UIView.animate(withDuration: 0.2) {
                subTypeView.layoutIfNeeded()
                subTypeView.tableView.reloadData()
            }
        }
        return subTypeView
    }
    
    @IBAction func closeAction(_ sender: UIButton) {
@@ -64,21 +72,33 @@
            self.alpha = 0
            self.layoutIfNeeded()
        } completion: { _ in
            self.clouse?("")
            let item = self.items[indexPath.row]
            self.clouse?(item)
            self.closeClouse?()
        }
    }
}
extension CourseSubTypeView:UITableViewDataSource{
    func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
        return 50
    }
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "_Common_1_TCell") as! Common_1_TCell
        let item = items[indexPath.row]
        cell.label_content.text = item.name
        if selectModel == nil{
            cell.isSelected = indexPath.row == 0
        }else{
            cell.isSelected = selectModel?.name == item.name
        }
        return cell
    }
    
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return 10
        return items.count
    }
    
    
WanPai/Root/Home/CCell/HomeCCell.swift
@@ -13,7 +13,6 @@
    
    override func awakeFromNib() {
        super.awakeFromNib()
        // Initialization code
    }
}
WanPai/Root/Home/CCell/HomeCCell.xib
@@ -1,9 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="21507" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="21701" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
    <device id="retina6_12" orientation="portrait" appearance="light"/>
    <dependencies>
        <deployment identifier="iOS"/>
        <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="21505"/>
        <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="21679"/>
        <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
    </dependencies>
    <objects>
@@ -16,7 +16,7 @@
                <rect key="frame" x="0.0" y="0.0" width="357" height="416"/>
                <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
                <subviews>
                    <imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="9vT-54-wYE">
                    <imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="9vT-54-wYE">
                        <rect key="frame" x="0.0" y="0.0" width="357" height="416"/>
                    </imageView>
                </subviews>
WanPai/Root/Home/Model/HomeModel.swift
New file
@@ -0,0 +1,35 @@
//
//  HomeModel.swift
//  WanPai
//
//  Created by 无故事王国 on 2023/7/7.
//
import Foundation
import HandyJSON
struct HomeStoreModel:HandyJSON{
    var isVip = 0
    var storeId = 0
    var name = ""
    var lon:Double = 0
    var lat:Double = 0
}
class  HomeStoreConfigModel:HandyJSON {
   required init() {}
    var type:HomeItemType = .none
    var isOpen:Int = 0
    var sort:Int = 0
    var backgroundImage:String = ""
    var defaultImg:UIImage?
    var radio:Double?
}
struct NormalSimpleModel:HandyJSON{
    var id = 0
    var name = ""
}
WanPai/Root/Home/VC/HomeVC.swift
@@ -1,32 +1,70 @@
//
//  HomeVC.swift
//  WanPai
//
//  Created by 杨锴 on 2023/6/8.
//
    //
    //  HomeVC.swift
    //  WanPai
    //
    //  Created by 杨锴 on 2023/6/8.
    //
import UIKit
import JQTools
import RxSwift
import SDWebImage
class HomeVC: BaseVC {
    //http://clips.vorwaerts-gmbh.de/big_buck_bunny.mp4
    //http://vjs.zencdn.net/v/oceans.mp4
    //https://media.w3.org/2010/05/sintel/trailer.mp4
    @IBOutlet weak var collectionView: UICollectionView!
class HomeVC: BaseVC,Refreshable{
    @IBOutlet weak var collectionView: BaseCollectionView!
    @IBOutlet weak var label_vipInfo: UILabel!
    private var layout:WaterFallFlowLayout!
    private var items = Array<String>()
    @IBOutlet weak var label_store: UILabel!
    private var items = Array<HomeStoreConfigModel>()
    private var storeModel:HomeStoreModel?
    override func viewDidLoad() {
        super.viewDidLoad()
        locationTool.startLocation { local in
            print("SUCCESS--->\(local.coordinate)")
        locationTool.startLocation { [weak self] local in
            locationTool.stopLocation()
        } errorClouse: { error in
            print("ERROR--->\(error.localizedDescription)")
            self?.getStoreInfo()
        } errorClouse: { [weak self] error in
            alertError(msg: "定位获取失败")
            self?.label_store.text = "定位获取失败"
            self?.getStoreInfo()
        }
        refreshStatusBind(to: collectionView,header: { [weak self] () in
            guard let weakSelf = self,weakSelf.storeModel != nil else {
                self?.refreshStatus.onNext(.endHeaderRefresh);return
            }
            Services.homeStoreConfig(storeId: weakSelf.storeModel!.storeId).subscribe(onNext: {data in
                if let models = data.data{
                    self?.items = models
                    let group = DispatchGroup()
                    for m in models{
                        let queue = DispatchQueue(label: "1")
                        queue.async(group: group) {
                            group.enter()
                            SDWebImageDownloader.shared.downloadImage(with: URL(string: m.backgroundImage)) { image, data, error, status in
                                if let i = image{
                                    m.radio = i.size.width / i.size.height
                                }
                                group.leave()
                            }
                        }
                    }
                    group.notify(queue: .main){
                        self?.refreshStatus.onNext(.endHeaderRefresh)
                        self?.collectionView.reloadData()
                    }
                }
            }).disposed(by: weakSelf.disposeBag)
        })
    }
    
    override func setUI() {
        view.backgroundColor = UIColor(hexStr: "EEF0F3")
@@ -40,9 +78,39 @@
        collectionView.dataSource = self
        collectionView.backgroundColor = .white
        collectionView.register(UINib(nibName: "HomeCCell", bundle: nil), forCellWithReuseIdentifier: "_HomeCCell")
        collectionView.jq_setEmptyView("无数据", image: UIImage(named: "icon_empty"), foregroundColor: .gray, clouse: nil)
    }
    private func getStoreInfo(){
        Services.homeInfo().subscribe(onNext: {[weak self] data in
            if let m = data.data{
                self?.label_store.text = m.name.isEmpty ? "门店获取失败":m.name
                var text = "欢迎来到 快乐运动俱乐部"
                if m.isVip == 0{text.append("\n加入我们 成为会员")}
                self?.label_vipInfo.text = text
                if m.storeId != 0{
                    self?.storeModel = m
                    self?.refreshStatus.onNext(.beingHeaderRefresh)
                }else{
                    self?.defaultData()
                }
            }
        }) { [weak self] error in
            self?.label_store.text = "门店获取失败"
            self?.defaultData()
        }.disposed(by: disposeBag)
    }
    private func defaultData(){
        for index in 1...8{
            items.append("b_\(index)")
            let type = HomeItemType(rawValue: index)!
            let m = HomeStoreConfigModel()
            m.type = type
            m.isOpen = 1
            m.sort = index
            m.radio = type.defaultImg.size.width / type.defaultImg.size.height
            items.append(m)
        }
        collectionView.reloadData()
    }
@@ -107,7 +175,8 @@
extension HomeVC:UICollectionViewDataSource{
    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "_HomeCCell", for: indexPath) as! HomeCCell
        cell.img.image = UIImage(named: items[indexPath.row])
        let item = items[indexPath.row]
        cell.img.sd_setImage(with: URL(string: item.backgroundImage), placeholderImage: item.type.defaultImg, options: .highPriority)
        return cell
    }
@@ -119,16 +188,13 @@
extension HomeVC: WaterFallLayoutDelegate{
    func waterFlowLayout(_ waterFlowLayout: WaterFallFlowLayout, itemHeight indexPath: IndexPath) -> CGFloat {
        if let tempImg = UIImage(named: items[indexPath.row]){
            let radio = tempImg.size.width / tempImg.size.height
            if radio >= 0.8{
                return 185
            }else{
                return 288
            }
        let item = items[indexPath.row]
        if (item.radio ?? 0) >= 0.8{
            return 185
        }else{
            return 288
        }
        return 288
    }
}
WanPai/Root/Home/VC/HomeVC.xib
@@ -1,9 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="21507" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="21701" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
    <device id="retina6_12" orientation="portrait" appearance="light"/>
    <dependencies>
        <deployment identifier="iOS"/>
        <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="21505"/>
        <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="21679"/>
        <capability name="Safe area layout guides" minToolsVersion="9.0"/>
        <capability name="System colors in document resources" minToolsVersion="11.0"/>
        <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
@@ -12,6 +12,8 @@
        <placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner" customClass="HomeVC" customModule="WanPai" customModuleProvider="target">
            <connections>
                <outlet property="collectionView" destination="ysy-N3-BCh" id="3mf-b9-Tj4"/>
                <outlet property="label_store" destination="VD5-cz-3Fs" id="azK-up-VpY"/>
                <outlet property="label_vipInfo" destination="Y4w-3W-3I4" id="Daq-hU-gwK"/>
                <outlet property="view" destination="i5M-Pr-FkT" id="sfx-zR-JGt"/>
            </connections>
        </placeholder>
@@ -130,7 +132,7 @@
                        <constraint firstItem="CWt-Cn-ccL" firstAttribute="top" secondItem="Y4w-3W-3I4" secondAttribute="bottom" constant="38" id="vwl-2A-Xaa"/>
                    </constraints>
                </view>
                <collectionView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" dataMode="none" translatesAutoresizingMaskIntoConstraints="NO" id="ysy-N3-BCh">
                <collectionView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" dataMode="none" translatesAutoresizingMaskIntoConstraints="NO" id="ysy-N3-BCh" customClass="BaseCollectionView" customModule="WanPai" customModuleProvider="target">
                    <rect key="frame" x="0.0" y="290.33333333333331" width="393" height="527.66666666666674"/>
                    <collectionViewFlowLayout key="collectionViewLayout" minimumLineSpacing="10" minimumInteritemSpacing="10" id="Hvc-jj-SAe">
                        <size key="itemSize" width="128" height="128"/>
WanPai/Root/Home/VC/JoinMemberIntroduceVC.swift
@@ -1,20 +1,31 @@
//
//  JoinMemberIntroduceVC.swift
//  WanPai
//
//  Created by 杨锴 on 2023/6/8.
//
    //
    //  JoinMemberIntroduceVC.swift
    //  WanPai
    //
    //  Created by 杨锴 on 2023/6/8.
    //
import UIKit
import QMUIKit
import WebKit
import JQTools
class JoinMemberIntroduceVC: BaseVC {
    @IBOutlet weak var btn_join: QMUIButton!
    @IBOutlet weak var webView: WKWebView!
    override func viewDidLoad() {
        super.viewDidLoad()
        title = "成为会员"
        Services.querySystemImg(type: .becomeVip).subscribe(onNext: {data in
            if let imgString = data.data{
                let html = "<img src='\(imgString)' width='\(JQ_ScreenW)' loading=eager/>"
                self.webView.loadHTMLString(html.jq_wrapHtml(), baseURL: nil)
            }
        }) { error in
        }.disposed(by: disposeBag)
    }
    
    override func setUI() {
WanPai/Root/Home/VC/JoinMemberIntroduceVC.xib
@@ -1,9 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="21507" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="21701" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
    <device id="retina6_12" orientation="portrait" appearance="light"/>
    <dependencies>
        <deployment identifier="iOS"/>
        <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="21505"/>
        <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="21679"/>
        <capability name="Named colors" minToolsVersion="9.0"/>
        <capability name="Safe area layout guides" minToolsVersion="9.0"/>
        <capability name="System colors in document resources" minToolsVersion="11.0"/>
@@ -14,6 +14,7 @@
            <connections>
                <outlet property="btn_join" destination="GjB-uh-zMR" id="lhq-Ch-tAZ"/>
                <outlet property="view" destination="i5M-Pr-FkT" id="sfx-zR-JGt"/>
                <outlet property="webView" destination="Hpl-hX-ZzE" id="7n6-xL-AAd"/>
            </connections>
        </placeholder>
        <placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
@@ -22,7 +23,7 @@
            <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
            <subviews>
                <wkWebView contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="Hpl-hX-ZzE">
                    <rect key="frame" x="0.0" y="59" width="393" height="759"/>
                    <rect key="frame" x="0.0" y="59" width="393" height="711"/>
                    <wkWebViewConfiguration key="configuration">
                        <audiovisualMediaTypes key="mediaTypesRequiringUserActionForPlayback" none="YES"/>
                        <wkPreferences key="preferences"/>
@@ -49,19 +50,19 @@
            <constraints>
                <constraint firstItem="Hpl-hX-ZzE" firstAttribute="leading" secondItem="fnl-2z-Ty3" secondAttribute="leading" id="7VF-r3-Yar"/>
                <constraint firstItem="fnl-2z-Ty3" firstAttribute="trailing" secondItem="Hpl-hX-ZzE" secondAttribute="trailing" id="Ax7-HK-yi9"/>
                <constraint firstItem="fnl-2z-Ty3" firstAttribute="bottom" secondItem="Hpl-hX-ZzE" secondAttribute="bottom" id="RiD-Rz-Uyy"/>
                <constraint firstItem="GjB-uh-zMR" firstAttribute="top" secondItem="Hpl-hX-ZzE" secondAttribute="bottom" id="GHn-U4-LTK"/>
                <constraint firstItem="GjB-uh-zMR" firstAttribute="leading" secondItem="fnl-2z-Ty3" secondAttribute="leading" id="Uyd-nn-6X1"/>
                <constraint firstItem="fnl-2z-Ty3" firstAttribute="trailing" secondItem="GjB-uh-zMR" secondAttribute="trailing" id="bdf-CQ-Uf4"/>
                <constraint firstItem="Hpl-hX-ZzE" firstAttribute="top" secondItem="fnl-2z-Ty3" secondAttribute="top" id="dce-pA-PVN"/>
                <constraint firstItem="fnl-2z-Ty3" firstAttribute="bottom" secondItem="GjB-uh-zMR" secondAttribute="bottom" id="m0F-H8-e5w"/>
            </constraints>
            <point key="canvasLocation" x="138" y="21"/>
            <point key="canvasLocation" x="136.64122137404578" y="20.422535211267608"/>
        </view>
    </objects>
    <resources>
        <image name="btn_add" width="20" height="20"/>
        <namedColor name="FE6E0D">
            <color red="0.99599999189376831" green="0.4309999942779541" blue="0.050999999046325684" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
            <color red="0.99199998378753662" green="0.53299999237060547" blue="0.0080000003799796104" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
        </namedColor>
        <systemColor name="systemBackgroundColor">
            <color white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
WanPai/Root/Login/VC/LoginRegOrForgotVC.swift
@@ -6,19 +6,19 @@
//
import UIKit
import QMUIKit
import JQTools
class LoginRegOrForgotVC: BaseVC {
    private var type:GetSMSCodeType!
    @IBOutlet weak var tf_phone: QMUITextField!
    @IBOutlet weak var tf_code: QMUITextField!
    @IBOutlet weak var tf_pwd: QMUITextField!
    
    enum UpdateType:String{
        case forgot = "忘记密码"
        case update = "修改密码"
        case register = "注册"
    }
    private var type:UpdateType!
    required init(type:UpdateType) {
    required init(type:GetSMSCodeType) {
        super.init(nibName: nil, bundle: nil)
        self.type = type
    }
@@ -26,13 +26,63 @@
    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    override func viewDidLoad() {
        super.viewDidLoad()
        title = type.rawValue
        title = type.titleStr
    }
    @IBAction func eyeAction(_ sender: UIButton) {
        sender.isSelected = !sender.isSelected
        tf_pwd.isSecureTextEntry = !sender.isSelected
    }
    @IBAction func completeAction(_ sender: UIButton) {
        guard !tf_phone.text!.isEmpty else {alertError(msg: tf_phone.placeholder!);return}
        guard tf_phone.text!.jq_isPhone else {alertError(msg: "请输入正确的手机号");return}
        guard !tf_code.text!.isEmpty else {alertError(msg: tf_code.placeholder!);return}
        guard !tf_pwd.text!.isEmpty else {alertError(msg: tf_pwd.placeholder!);return}
        guard tf_pwd.text!.jq_isComplexPassword else {alertError(msg: "请输入6-18位包含数字和字母的密码");return}
        let phone = tf_phone.text!
        let pwd = tf_pwd.text!
        let code = tf_code.text!
        switch type{
            case .register:
                Services.register(phone: phone, password: pwd, code: code).subscribe(onNext: { result in
                    alertSuccess(msg: "注册成功")
                    DispatchQueue.main.asyncAfter(wallDeadline: .now()+1) {
                        app.registerAndLoginSuccess()
                    }
                }).disposed(by: disposeBag)
            case .forgotPwd:
                Services.forgetPwd(phone: phone, password: pwd, code: code).subscribe(onNext: { result in
                    alertSuccess(msg: "修改成功")
                    DispatchQueue.main.asyncAfter(wallDeadline: .now()+1) {
                        self.navigationController?.popViewController()
                    }
                }).disposed(by: disposeBag)
            case .updatePwd:
                Services.updatePwd(phone: phone, password: pwd, code: code).subscribe(onNext: { result in
                    alertSuccess(msg: "修改成功")
                    DispatchQueue.main.asyncAfter(wallDeadline: .now()+1) {
                        self.navigationController?.popViewController()
                    }
                }).disposed(by: disposeBag)
            default:break
        }
    }
    @IBAction func getCodeAction(_ sender: UIButton) {
        guard !tf_phone.text!.isEmpty else {alertError(msg: tf_phone.placeholder!);return}
        guard tf_phone.text!.jq_isPhone else {alertError(msg: "请输入正确的手机号");return}
        Services.getSMSCode(phone: tf_phone.text!, type: type).subscribe(onNext: {result in
            sender.jq_openCountDown()
        }).disposed(by: disposeBag)
    }
    override var preferredStatusBarStyle: UIStatusBarStyle{
        return .default
    }
WanPai/Root/Login/VC/LoginRegOrForgotVC.xib
@@ -1,9 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="21507" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="21701" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
    <device id="retina6_12" orientation="portrait" appearance="light"/>
    <dependencies>
        <deployment identifier="iOS"/>
        <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="21505"/>
        <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="21679"/>
        <capability name="Named colors" minToolsVersion="9.0"/>
        <capability name="Safe area layout guides" minToolsVersion="9.0"/>
        <capability name="System colors in document resources" minToolsVersion="11.0"/>
@@ -12,6 +12,9 @@
    <objects>
        <placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner" customClass="LoginRegOrForgotVC" customModule="WanPai" customModuleProvider="target">
            <connections>
                <outlet property="tf_code" destination="gNj-6t-p9o" id="dc4-A0-9gm"/>
                <outlet property="tf_phone" destination="t2b-ES-vps" id="chL-vl-tdC"/>
                <outlet property="tf_pwd" destination="xxp-hE-Y3y" id="ce7-Z5-2g7"/>
                <outlet property="view" destination="i5M-Pr-FkT" id="sfx-zR-JGt"/>
            </connections>
        </placeholder>
@@ -79,13 +82,16 @@
                                </userDefinedRuntimeAttribute>
                            </userDefinedRuntimeAttributes>
                        </textField>
                        <button hidden="YES" opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="8ND-Q2-rU3">
                        <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="8ND-Q2-rU3">
                            <rect key="frame" x="231" y="6.6666666666666856" width="62" height="27"/>
                            <fontDescription key="fontDescription" type="system" weight="medium" pointSize="12"/>
                            <inset key="imageEdgeInsets" minX="0.0" minY="0.0" maxX="2.2250738585072014e-308" maxY="0.0"/>
                            <state key="normal" title="获取验证码">
                                <color key="titleColor" red="0.38823529410000002" green="0.74117647060000003" blue="0.85882352939999995" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
                            </state>
                            <connections>
                                <action selector="getCodeAction:" destination="-1" eventType="touchUpInside" id="Xm2-2J-Iz6"/>
                            </connections>
                        </button>
                    </subviews>
                    <color key="backgroundColor" red="0.96470588239999999" green="0.96470588239999999" blue="0.96470588239999999" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
@@ -109,7 +115,7 @@
                <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="gqc-3H-F7Y">
                    <rect key="frame" x="40" y="314" width="313" height="40"/>
                    <subviews>
                        <imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="icon_login_code" translatesAutoresizingMaskIntoConstraints="NO" id="DwZ-DK-k3H">
                        <imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="icon_login_pwd" translatesAutoresizingMaskIntoConstraints="NO" id="DwZ-DK-k3H">
                            <rect key="frame" x="31" y="11" width="15" height="18"/>
                        </imageView>
                        <textField opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="248" contentHorizontalAlignment="left" contentVerticalAlignment="center" placeholder="请输入密码" textAlignment="natural" minimumFontSize="17" translatesAutoresizingMaskIntoConstraints="NO" id="xxp-hE-Y3y" customClass="QMUITextField">
@@ -130,6 +136,9 @@
                            <inset key="imageEdgeInsets" minX="0.0" minY="0.0" maxX="2.2250738585072014e-308" maxY="0.0"/>
                            <state key="normal" image="icon_login_eye_c"/>
                            <state key="selected" image="icon_login_eye"/>
                            <connections>
                                <action selector="eyeAction:" destination="-1" eventType="touchUpInside" id="c6c-H9-Pe2"/>
                            </connections>
                        </button>
                    </subviews>
                    <color key="backgroundColor" red="0.96470588239999999" green="0.96470588239999999" blue="0.96470588239999999" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
@@ -166,6 +175,9 @@
                            <real key="value" value="20"/>
                        </userDefinedRuntimeAttribute>
                    </userDefinedRuntimeAttributes>
                    <connections>
                        <action selector="completeAction:" destination="-1" eventType="touchUpInside" id="T4h-wV-1He"/>
                    </connections>
                </button>
            </subviews>
            <viewLayoutGuide key="safeArea" id="fnl-2z-Ty3"/>
@@ -197,8 +209,9 @@
        <image name="icon_login_eye" width="23" height="14"/>
        <image name="icon_login_eye_c" width="22" height="9"/>
        <image name="icon_login_phone" width="16" height="18"/>
        <image name="icon_login_pwd" width="15" height="18"/>
        <namedColor name="FE6E0D">
            <color red="0.99599999189376831" green="0.4309999942779541" blue="0.050999999046325684" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
            <color red="0.99199998378753662" green="0.53299999237060547" blue="0.0080000003799796104" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
        </namedColor>
        <systemColor name="systemBackgroundColor">
            <color white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
WanPai/Root/Login/VC/LoginVC.swift
@@ -10,10 +10,6 @@
import QMUIKit
import JQTools
private enum LoginType{
    case pwd,smsCode
}
class LoginVC: BaseVC {
    
    @IBOutlet weak var btn_pwdLogin: UIButton!
@@ -29,7 +25,8 @@
    @IBOutlet weak var btn_register: UIButton!
    @IBOutlet weak var cons_registerCenterX: NSLayoutConstraint!
    @IBOutlet weak var cons_loginCenterX: NSLayoutConstraint!
    @IBOutlet weak var btn_reader: UIButton!
    @IBOutlet weak var cons_loginWidth: NSLayoutConstraint!
    private let loginType = BehaviorRelay<LoginType>(value: .pwd)
@@ -95,8 +92,10 @@
        UIView.animate(withDuration: 0.4) {
            self.view.layoutIfNeeded()
            self.btn_login.setTitle(str, for: .normal)
        } completion: { _ in
            self.tf_verify.text = ""
            self.view.endEditing(false)
        }
    }
    
    @IBAction func eyeAction(_ sender: UIButton) {
@@ -106,49 +105,40 @@
        }
    }
    
    @IBAction func loginAction(_ sender: UIButton) {
        let snapView = screnDelegate?.window?.snapshotView(afterScreenUpdates: true)
        let tabBar = BaseTabBarVC()
        let homeNav = BaseNav(rootViewController: HomeVC())
        homeNav.tabBarItem = UITabBarItem(title: "加入玩湃", image: UIImage(named: "tabbar_home"), selectedImage: UIImage(named: "tabbar_home_s"))
    @IBAction func getCodeAction(_ sender: UIButton) {
        guard !tf_phone.text!.isEmpty else {alertError(msg: tf_phone.placeholder!);return}
        guard tf_phone.text!.jq_isPhone else {alertError(msg: "请输入正确的手机号");return}
        Services.getSMSCode(phone: tf_phone.text!, type: .login).subscribe(onNext: {result in
            sender.jq_openCountDown()
        }) { error in
            alertError(msg: error.localizedDescription)
        }.disposed(by: disposeBag)
    }
//        let clouseNav = BaseNav(rootViewController: CourseVC())
        let clouseNav = BaseNav(rootViewController: CourseInfoVC())
        clouseNav.tabBarItem = UITabBarItem(title: "开始上课", image: UIImage(named: "tabbar_course"), selectedImage: UIImage(named: "tabbar_course_s"))
        let welfareVCNav = BaseNav(rootViewController: WelfareVC())
        welfareVCNav.tabBarItem = UITabBarItem(title: "使用福利", image: UIImage(named: "tabbar_welfare"), selectedImage: UIImage(named: "tabbar_welfare_s"))
        let searchVCNav = BaseNav(rootViewController: SearchVC())
        searchVCNav.tabBarItem = UITabBarItem(title: "搜索玩湃", image: UIImage(named: "tabbar_search"), selectedImage: UIImage(named: "tabbar_search_s"))
        tabBar.viewControllers = [homeNav,clouseNav,welfareVCNav,searchVCNav]
        screnDelegate?.window?.rootViewController = tabBar
        screnDelegate?.window?.rootViewController?.view.addSubview(snapView!)
        screnDelegate?.window?.makeKeyAndVisible()
        UIView.animate(withDuration: 1.5) {
            snapView?.alpha = 0
            snapView?.transform3D = CATransform3DMakeScale(1.5, 1.5, 1.5)
        } completion: { _ in
            snapView?.removeFromSuperview()
        }
    @IBAction func loginAction(_ sender: UIButton) {
        let type = loginType.value
        guard !tf_phone.text!.isEmpty else {alertError(msg: tf_phone.placeholder!);return}
        guard !tf_verify.text!.isEmpty else {alertError(msg: tf_verify.placeholder!);return}
        guard btn_reader.isSelected else {alert(msg: "请先仔细阅读并同意协议");return}
        Services.login(phone: tf_phone.text!, verity: tf_verify.text!, type: type).subscribe(onNext: {data in
            if let token = data.data{
                UserViewModel.saveToken(token)
                app.registerAndLoginSuccess()
            }
        }) { error in
        }.disposed(by: disposeBag)
    }
    
    @IBAction func updatePwdAction(_ sender: UIButton) {
        let vc = LoginRegOrForgotVC(type: .update)
        let vc = LoginRegOrForgotVC(type: .updatePwd)
        push(vc: vc)
    }
    
    @IBAction func forgotPwdAction(_ sender: UIButton) {
        let vc = LoginRegOrForgotVC(type: .forgot)
        let vc = LoginRegOrForgotVC(type: .forgotPwd)
        push(vc: vc)
    }
    
WanPai/Root/Login/VC/LoginVC.xib
@@ -1,9 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="21507" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="21701" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
    <device id="retina6_12" orientation="portrait" appearance="light"/>
    <dependencies>
        <deployment identifier="iOS"/>
        <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="21505"/>
        <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="21679"/>
        <capability name="Named colors" minToolsVersion="9.0"/>
        <capability name="Safe area layout guides" minToolsVersion="9.0"/>
        <capability name="System colors in document resources" minToolsVersion="11.0"/>
@@ -16,6 +16,7 @@
                <outlet property="btn_getCode" destination="Peu-H2-2Bj" id="Tos-ZB-3it"/>
                <outlet property="btn_login" destination="NQ0-2r-DbZ" id="0lx-ai-KGD"/>
                <outlet property="btn_pwdLogin" destination="fEr-ZJ-pMj" id="adD-fy-ix2"/>
                <outlet property="btn_reader" destination="jpR-VA-PYM" id="T1z-5v-IKe"/>
                <outlet property="btn_register" destination="A58-cL-JDg" id="6oc-zY-p32"/>
                <outlet property="btn_smsCodeLogin" destination="Bgw-Aw-FZm" id="Jde-9o-6wl"/>
                <outlet property="btn_wechat" destination="AA4-J4-8iR" id="Rdp-vy-GdD"/>
@@ -192,6 +193,9 @@
                            <state key="normal" title="获取验证码">
                                <color key="titleColor" red="0.38823529411764707" green="0.74117647058823533" blue="0.85882352941176465" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
                            </state>
                            <connections>
                                <action selector="getCodeAction:" destination="-1" eventType="touchUpInside" id="b4t-WU-j3J"/>
                            </connections>
                        </button>
                    </subviews>
                    <color key="backgroundColor" red="0.96470588239999999" green="0.96470588239999999" blue="0.96470588239999999" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
@@ -258,7 +262,7 @@
                        </userDefinedRuntimeAttribute>
                    </userDefinedRuntimeAttributes>
                    <connections>
                        <action selector="loginAction:" destination="-1" eventType="touchUpInside" id="w5q-4Z-SHK"/>
                        <action selector="loginAction:" destination="-1" eventType="touchUpInside" id="2Hk-H5-S04"/>
                    </connections>
                </button>
                <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="jpR-VA-PYM">
@@ -275,10 +279,10 @@
                    </connections>
                </button>
                <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="mZh-Vi-57o">
                    <rect key="frame" x="0.0" y="499" width="393" height="319"/>
                    <rect key="frame" x="0.0" y="716" width="393" height="102"/>
                    <subviews>
                        <stackView opaque="NO" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="ikk-sm-4Sm">
                            <rect key="frame" x="146.66666666666666" y="179" width="100" height="50"/>
                            <rect key="frame" x="146.66666666666666" y="42" width="100" height="50"/>
                            <subviews>
                                <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="AA4-J4-8iR" customClass="QMUIButton">
                                    <rect key="frame" x="0.0" y="0.0" width="100" height="50"/>
@@ -294,7 +298,7 @@
                            </subviews>
                        </stackView>
                        <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="其他登录方式" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="cqp-2p-rC6">
                            <rect key="frame" x="159.66666666666666" y="147" width="73.666666666666657" height="17"/>
                            <rect key="frame" x="159.66666666666666" y="10" width="73.666666666666657" height="17"/>
                            <constraints>
                                <constraint firstAttribute="height" constant="17" id="DBH-wO-NS0"/>
                            </constraints>
@@ -306,7 +310,8 @@
                    <color key="backgroundColor" systemColor="systemBackgroundColor"/>
                    <constraints>
                        <constraint firstItem="ikk-sm-4Sm" firstAttribute="centerX" secondItem="cqp-2p-rC6" secondAttribute="centerX" id="0xX-m5-mrX"/>
                        <constraint firstAttribute="bottom" secondItem="ikk-sm-4Sm" secondAttribute="bottom" constant="90" id="egz-uu-9vA"/>
                        <constraint firstItem="cqp-2p-rC6" firstAttribute="top" secondItem="mZh-Vi-57o" secondAttribute="top" constant="10" id="JPx-ei-th8"/>
                        <constraint firstAttribute="bottom" secondItem="ikk-sm-4Sm" secondAttribute="bottom" constant="10" id="egz-uu-9vA"/>
                        <constraint firstItem="ikk-sm-4Sm" firstAttribute="top" secondItem="cqp-2p-rC6" secondAttribute="bottom" constant="15" id="m32-Te-28i"/>
                        <constraint firstItem="ikk-sm-4Sm" firstAttribute="centerX" secondItem="mZh-Vi-57o" secondAttribute="centerX" id="sxJ-Mz-EGJ"/>
                    </constraints>
@@ -327,6 +332,7 @@
            <constraints>
                <constraint firstItem="Ej3-Zy-UxP" firstAttribute="centerX" secondItem="fnl-2z-Ty3" secondAttribute="centerX" id="06n-Gd-wg4"/>
                <constraint firstItem="fnl-2z-Ty3" firstAttribute="trailing" secondItem="mZh-Vi-57o" secondAttribute="trailing" id="5PZ-du-NJ4"/>
                <constraint firstItem="NQ0-2r-DbZ" firstAttribute="bottom" secondItem="A58-cL-JDg" secondAttribute="bottom" id="96l-De-ULg"/>
                <constraint firstItem="cAB-q2-f9Z" firstAttribute="top" secondItem="38m-zi-L1d" secondAttribute="bottom" constant="32" id="BJR-4U-Mqg"/>
                <constraint firstItem="1LE-kf-RCn" firstAttribute="leading" secondItem="ixo-tJ-9cE" secondAttribute="leading" id="C94-6l-8Sz"/>
                <constraint firstItem="NQ0-2r-DbZ" firstAttribute="centerY" secondItem="A58-cL-JDg" secondAttribute="centerY" id="ELW-lb-UMU"/>
@@ -340,7 +346,6 @@
                <constraint firstItem="ixo-tJ-9cE" firstAttribute="top" secondItem="cAB-q2-f9Z" secondAttribute="bottom" constant="30" id="THc-e6-Bko"/>
                <constraint firstItem="fnl-2z-Ty3" firstAttribute="trailing" secondItem="ixo-tJ-9cE" secondAttribute="trailing" constant="40" id="TzU-Nh-o64"/>
                <constraint firstItem="jpR-VA-PYM" firstAttribute="top" secondItem="A58-cL-JDg" secondAttribute="bottom" constant="20" id="Ujc-Kg-bWe"/>
                <constraint firstItem="mZh-Vi-57o" firstAttribute="top" secondItem="BqB-Az-Ez1" secondAttribute="bottom" constant="5" id="dMK-2O-N4o"/>
                <constraint firstItem="1LE-kf-RCn" firstAttribute="top" secondItem="ixo-tJ-9cE" secondAttribute="bottom" constant="20" id="h5h-2F-FmM"/>
                <constraint firstItem="38m-zi-L1d" firstAttribute="top" secondItem="fnl-2z-Ty3" secondAttribute="top" constant="20" id="iPe-ep-hvl"/>
                <constraint firstItem="A58-cL-JDg" firstAttribute="top" secondItem="Ej3-Zy-UxP" secondAttribute="bottom" constant="28" id="j1g-QM-Spl"/>
@@ -351,6 +356,7 @@
                <constraint firstItem="BqB-Az-Ez1" firstAttribute="leading" secondItem="jpR-VA-PYM" secondAttribute="trailing" constant="2" id="wEr-Lg-muD"/>
                <constraint firstItem="ixo-tJ-9cE" firstAttribute="leading" secondItem="fnl-2z-Ty3" secondAttribute="leading" constant="40" id="wT0-yN-RM8"/>
                <constraint firstItem="jpR-VA-PYM" firstAttribute="top" secondItem="BqB-Az-Ez1" secondAttribute="top" constant="5" id="x9D-NQ-ac9"/>
                <constraint firstItem="NQ0-2r-DbZ" firstAttribute="top" secondItem="A58-cL-JDg" secondAttribute="top" id="zD3-hH-bHY"/>
            </constraints>
            <point key="canvasLocation" x="136.64122137404578" y="20.422535211267608"/>
        </view>
@@ -368,7 +374,7 @@
            <color red="0.31799998879432678" green="0.31799998879432678" blue="0.31799998879432678" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
        </namedColor>
        <namedColor name="FE6E0D">
            <color red="0.99599999189376831" green="0.4309999942779541" blue="0.050999999046325684" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
            <color red="0.99199998378753662" green="0.53299999237060547" blue="0.0080000003799796104" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
        </namedColor>
        <systemColor name="labelColor">
            <color red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
WanPai/Root/Other/TCell/Common_1_TCell.swift
@@ -9,9 +9,16 @@
class Common_1_TCell: UITableViewCell {
    @IBOutlet weak var label_content: UILabel!
    @IBOutlet weak var img_select: UIImageView!
    override func awakeFromNib() {
        super.awakeFromNib()
        selectionStyle = .none
    }
    override var isSelected: Bool{
        didSet{
            img_select.image = isSelected ? UIImage(named: "btn_choose_s"):UIImage(named: "btn_choose")
        }
    }
}
WanPai/Root/Other/TCell/Common_1_TCell.xib
@@ -1,9 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="21507" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="21701" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
    <device id="retina6_12" orientation="portrait" appearance="light"/>
    <dependencies>
        <deployment identifier="iOS"/>
        <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="21505"/>
        <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="21679"/>
        <capability name="Safe area layout guides" minToolsVersion="9.0"/>
        <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
    </dependencies>
@@ -49,6 +49,10 @@
                </constraints>
            </tableViewCellContentView>
            <viewLayoutGuide key="safeArea" id="njF-e1-oar"/>
            <connections>
                <outlet property="img_select" destination="IsM-9J-Fsh" id="Bbf-CV-eTm"/>
                <outlet property="label_content" destination="P0g-n9-6rY" id="YeF-au-htc"/>
            </connections>
            <point key="canvasLocation" x="170.22900763358777" y="-25.35211267605634"/>
        </tableViewCell>
    </objects>
WanPai/Root/Search/VC/SearchStoreDetailVC.swift
@@ -55,7 +55,7 @@
            let vc = YardListVC()
            push(vc: vc)
        }else{
            let vc = CourseDetailVC()
            let vc = CourseDetailVC(id: 0)
            push(vc: vc)
        }
    }
WanPai/Root/Search/VC/SearchStoreListVC.swift
@@ -43,7 +43,8 @@
    @IBAction func cityAction(_ sender: QMUIButton) {
        guard !sender.isSelected else {return}
        sender.isSelected = true
        CourseSubTypeView.show(inView: self.view, afterView: stackView, items: ["足球课程","篮球课程","羽毛球课程","网球课程"]) { str in
        let items = Array<NormalSimpleModel>()
        CourseSubTypeView.show(inView: self.view, afterView: stackView, items:items) { m in
            sender.isSelected = false
        } closeClouse: {
WanPai/Root/Welfare/VC/WelfareBillListVC.swift
@@ -75,7 +75,7 @@
        btn.titleLabel?.font = UIFont.systemFont(ofSize: 16)
        btn.jq_borderWidth = 1
        btn.jq_borderColor = UIColor(hexStr: "#D5D1D1")
        btn.cornerRadius = 4
        btn.jq_cornerRadius = 4
        btn.setTitle("全部记录", for: .normal)
        btn.setImage(UIImage(named: "icon_down_arrow"), for: .normal)
        btn.imagePosition = .right
WanPai/Root/Welfare/VC/WelfareCouponsListVC.swift
@@ -61,7 +61,7 @@
        btn.spacingBetweenImageAndTitle = 37
        btn.jq_borderColor = UIColor(hexStr: "#D5D1D1")
        btn.jq_borderWidth = 1
        btn.cornerRadius = 4
        btn.jq_cornerRadius = 4
        btn.backgroundColor = .white
        return btn
    }()
WanPai/Root/Welfare/VC/WelfareExchangeRecordListVC.swift
@@ -121,7 +121,8 @@
        if let btn = funcView.viewWithTag(1000) as? QMUIButton{
            guard !btn.isSelected else {return}
            btn.isSelected = true
            CourseSubTypeView.show(inView: self.view, afterView: funcView, items: ["实体商品","课包商品","门票商品","优惠券"]) { str in
            let items = Array<NormalSimpleModel>()
            CourseSubTypeView.show(inView: self.view, afterView: funcView, items: items) { m in
                btn.isSelected = false
            } closeClouse: {
WanPai/Root/Welfare/View/CoinStoreHeadView.swift
@@ -31,7 +31,8 @@
    @IBAction func resortAction(_ sender: QMUIButton) {
        guard !sender.isSelected else {return}
        sender.isSelected = true
        CourseSubTypeView.show(inView: self.innerView, afterView: self, items: ["积分从高到底","积分从低到高","兑换从高到底"]) { str in
        let items = Array<NormalSimpleModel>()
        CourseSubTypeView.show(inView: self.innerView, afterView: self, items: items) { m in
            sender.isSelected = false
        } closeClouse: {
@@ -42,7 +43,8 @@
    @IBAction func typeAction(_ sender: UIButton) {
        guard !sender.isSelected else {return}
        sender.isSelected = true
        CourseSubTypeView.show(inView: self.innerView, afterView: self, items: ["实体商品","课包商品","门票商品","优惠券"]) { str in
        let items = Array<NormalSimpleModel>()
        CourseSubTypeView.show(inView: self.innerView, afterView: self, items: items) {m in
            sender.isSelected = false
        } closeClouse: {
WanPai/Root/Yard/VC/YardListVC.swift
@@ -60,7 +60,8 @@
    @IBAction func yardTypeAction(_ sender: QMUIButton) {
        guard !sender.isSelected else {return}
        sender.isSelected = true
        CourseSubTypeView.show(inView: self.view, afterView: view_top, items: ["足球场","篮球场","网球场"]) { str in
        let items = Array<NormalSimpleModel>()
        CourseSubTypeView.show(inView: self.view, afterView: view_top, items: items) { m in
            sender.isSelected = false
        } closeClouse: {
@@ -81,7 +82,8 @@
    @IBAction func inStoreAction(_ sender: QMUIButton) {
        guard !sender.isSelected else {return}
        sender.isSelected = true
        CourseSubTypeView.show(inView: self.view, afterView: view_top, items: ["其他门店","其他门店","其他门店"]) { str in
        let items = Array<NormalSimpleModel>()
        CourseSubTypeView.show(inView: self.view, afterView: view_top, items: items) { m in
            sender.isSelected = false
        } closeClouse: {
WanPai/SceneDelegate.swift
@@ -6,6 +6,7 @@
//
import UIKit
import SVProgressHUD
class SceneDelegate: UIResponder, UIWindowSceneDelegate {
    
@@ -15,9 +16,34 @@
        guard let windowScene = (scene as? UIWindowScene) else { return }
        window = UIWindow(windowScene: windowScene)
        window?.frame = windowScene.coordinateSpace.bounds
        let nav = LoginNav(rootViewController: LoginVC())
        window?.rootViewController =  nav
        window?.makeKeyAndVisible()
        if UserViewModel.getToken() != nil{
            let tabBar = BaseTabBarVC()
            let homeNav = BaseNav(rootViewController: HomeVC())
            homeNav.tabBarItem = UITabBarItem(title: "加入玩湃", image: UIImage(named: "tabbar_home"), selectedImage: UIImage(named: "tabbar_home_s"))
            let clouseNav = BaseNav(rootViewController: CourseVC())
            clouseNav.tabBarItem = UITabBarItem(title: "开始上课", image: UIImage(named: "tabbar_course"), selectedImage: UIImage(named: "tabbar_course_s"))
            let welfareVCNav = BaseNav(rootViewController: WelfareVC())
            welfareVCNav.tabBarItem = UITabBarItem(title: "使用福利", image: UIImage(named: "tabbar_welfare"), selectedImage: UIImage(named: "tabbar_welfare_s"))
            let searchVCNav = BaseNav(rootViewController: SearchVC())
            searchVCNav.tabBarItem = UITabBarItem(title: "搜索玩湃", image: UIImage(named: "tabbar_search"), selectedImage: UIImage(named: "tabbar_search_s"))
            tabBar.viewControllers = [homeNav,clouseNav,welfareVCNav,searchVCNav]
            window?.rootViewController = tabBar
            window?.makeKeyAndVisible()
        }else{
            let nav = LoginNav(rootViewController: LoginVC())
            window?.rootViewController =  nav
            window?.makeKeyAndVisible()
        }
        SVProgressHUD.setContainerView(window)
        SVProgressHUD.setDefaultStyle(.dark)
        SVProgressHUD.setMinimumDismissTimeInterval(1.5)
        SVProgressHUD.setMaximumDismissTimeInterval(30.0)
        
        if #available(iOS 13.0, *) {
            self.window?.overrideUserInterfaceStyle = .light
@@ -44,7 +70,5 @@
    func sceneDidEnterBackground(_ scene: UIScene) {
        
    }
}
WanPai/ViewModel/UserModel.swift
New file
@@ -0,0 +1,26 @@
//
//  UserModel.swift
//  WanPai
//
//  Created by 无故事王国 on 2023/7/7.
//
import Foundation
import HandyJSON
import CoreLocation
final class UserViewModel{
    static func getToken()->String?{
        return UserDefaults.standard.object(forKey: "_userToken") as? String
    }
    static func saveToken(_ token:String){
        UserDefaults.standard.set(token, forKey: "_userToken")
        UserDefaults.standard.synchronize()
    }
    static func clearToken(){
        UserDefaults.standard.set(nil, forKey: "_userToken")
        UserDefaults.standard.synchronize()
    }
}