杨锴
2024-10-24 e821bea13d9f20905bba3972c4e9c4964994db5d
fix API TEST
49个文件已修改
3个文件已删除
8个文件已添加
1797 ■■■■ 已修改文件
Pods/Pods.xcodeproj/project.pbxproj 12 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
XQMuse.xcodeproj/project.pbxproj 48 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
XQMuse/AppDelegate.swift 41 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
XQMuse/Assets.xcassets/Btns/btn_share_1.imageset/btn_share@2x.png 补丁 | 查看 | 原始文档 | blame | 历史
XQMuse/Assets.xcassets/Btns/btn_share_1.imageset/btn_share@3x.png 补丁 | 查看 | 原始文档 | blame | 历史
XQMuse/Assets.xcassets/Placeholder/bg_guide_home.imageset/Contents.json 22 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
XQMuse/Assets.xcassets/Placeholder/bg_guide_home.imageset/组 20@2x.png 补丁 | 查看 | 原始文档 | blame | 历史
XQMuse/Assets.xcassets/Placeholder/bg_guide_home.imageset/组 20@3x.png 补丁 | 查看 | 原始文档 | blame | 历史
XQMuse/Base/BaseNav.swift 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
XQMuse/Config/Def.swift 3 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
XQMuse/Config/EqualCellSpaceFlowLayout.swift 136 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
XQMuse/Config/Layouts/HoverHeaderFlowLayout.swift 99 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
XQMuse/Config/StoreKit/InPurchaseManager.swift 305 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
XQMuse/Config/StoreKit/XQMuseStoreKit.storekit 247 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
XQMuse/Config/WeChatTools.swift 205 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
XQMuse/Config/XQMuse-Bridging-Header.h 12 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
XQMuse/Info.plist 21 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
XQMuse/Root/Course/CCell/CourseOfficalCommendTopCCell.swift 6 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
XQMuse/Root/Course/CourseVC.swift 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
XQMuse/Root/Course/VC/CourseDetialVC.swift 47 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
XQMuse/Root/Course/VC/CourseDetialVideoVC.swift 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
XQMuse/Root/Course/VC/CourseVCOfficalCommentVC.swift 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
XQMuse/Root/Home/CCell/HomeRelaxBanner_2_1_CCell.swift 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
XQMuse/Root/Home/CCell/HomeRelaxBanner_2_1_CCell.xib 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
XQMuse/Root/Home/CCell/HomeRelaxBanner_2_CCell.swift 21 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
XQMuse/Root/Home/CCell/HomeRelaxBanner_2_CCell.xib 35 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
XQMuse/Root/Home/CCell/Home_Style_4_Inner_1_CCell.swift 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
XQMuse/Root/Home/CCell/Home_Style_4_Inner_1_CCell.xib 11 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
XQMuse/Root/Home/HomeVC.swift 27 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
XQMuse/Root/Home/TCell/Home_Style_2_TCell.swift 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
XQMuse/Root/Home/TCell/Home_Style_2_TCell.xib 7 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
XQMuse/Root/Home/VC/CommentListVC.swift 19 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
XQMuse/Root/Home/VC/HomeItemDetailVC.swift 32 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
XQMuse/Root/Home/VC/HomeItemDetailVC.xib 9 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
XQMuse/Root/Home/VC/PaymentOrderResultVC.swift 13 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
XQMuse/Root/Home/VC/PaymentOrderVC.swift 24 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
XQMuse/Root/Home/VC/SearchContentVC.swift 96 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
XQMuse/Root/Home/VC/SearchVC.swift 44 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
XQMuse/Root/Home/VC/SearchVC.xib 10 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
XQMuse/Root/Home/View/PaymentOrderResultTopView.swift 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
XQMuse/Root/Login/LoginVC.swift 7 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
XQMuse/Root/Login/LoginVC.xib 27 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
XQMuse/Root/Login/VC/ForgotPasswordInputCodeVC.swift 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
XQMuse/Root/Login/VC/RegisterVC.swift 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
XQMuse/Root/Login/VC/UpdatePhoneVC.swift 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
XQMuse/Root/Me/MeVC.xib 8 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
XQMuse/Root/Me/VC/AddBankInfoVC.swift 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
XQMuse/Root/Me/VC/BindPhone_2_VC.swift 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
XQMuse/Root/Network/Models.swift 5 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
XQMuse/Root/Network/NetworkRequest.swift 27 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
XQMuse/Root/Network/Services.swift 37 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
XQMuse/Root/Other/View/CommonBannerView.swift 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
XQMuse/Root/Pavilion/VC/PavilionDetailVC.xib 8 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
XQMuse/Root/Pavilion/VC/PavilionSearchVC.swift 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
XQMuse/Root/Plans/PlanGuideVC.swift 27 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
XQMuse/Root/Plans/PlanGuide_2_VC.swift 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
XQMuse/Root/Plans/PlanGuide_3_VC.swift 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
XQMuse/Root/ViewModel/RefreshModel.swift 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
XQMuse/SceneDelegate.swift 47 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
XQMuse/XQMuse.entitlements 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Pods/Pods.xcodeproj/project.pbxproj
@@ -13214,7 +13214,7 @@
                GCC_PREFIX_HEADER = "Target Support Files/ObjectMapper/ObjectMapper-prefix.pch";
                INFOPLIST_FILE = "Target Support Files/ObjectMapper/ObjectMapper-Info.plist";
                INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
                IPHONEOS_DEPLOYMENT_TARGET = 10.0;
                IPHONEOS_DEPLOYMENT_TARGET = 10;
                LD_RUNPATH_SEARCH_PATHS = (
                    "$(inherited)",
                    "@executable_path/Frameworks",
@@ -14164,7 +14164,7 @@
                GCC_PREFIX_HEADER = "Target Support Files/ObjectMapper/ObjectMapper-prefix.pch";
                INFOPLIST_FILE = "Target Support Files/ObjectMapper/ObjectMapper-Info.plist";
                INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
                IPHONEOS_DEPLOYMENT_TARGET = 10.0;
                IPHONEOS_DEPLOYMENT_TARGET = 10;
                LD_RUNPATH_SEARCH_PATHS = (
                    "$(inherited)",
                    "@executable_path/Frameworks",
@@ -14761,7 +14761,7 @@
                DEVELOPMENT_TEAM = 5ZV937VB25;
                IBSC_MODULE = ObjectMapper;
                INFOPLIST_FILE = "Target Support Files/ObjectMapper/ResourceBundle-Privacy-ObjectMapper-Info.plist";
                IPHONEOS_DEPLOYMENT_TARGET = 10.0;
                IPHONEOS_DEPLOYMENT_TARGET = 13.0;
                PRODUCT_BUNDLE_IDENTIFIER = com.sinata.XQMuse.test;
                PRODUCT_NAME = Privacy;
                SDKROOT = iphoneos;
@@ -15103,7 +15103,7 @@
                DEVELOPMENT_TEAM = 5ZV937VB25;
                IBSC_MODULE = ObjectMapper;
                INFOPLIST_FILE = "Target Support Files/ObjectMapper/ResourceBundle-Privacy-ObjectMapper-Info.plist";
                IPHONEOS_DEPLOYMENT_TARGET = 10.0;
                IPHONEOS_DEPLOYMENT_TARGET = 13.0;
                PRODUCT_BUNDLE_IDENTIFIER = com.sinata.XQMuse.test;
                PRODUCT_NAME = Privacy;
                SDKROOT = iphoneos;
@@ -15269,7 +15269,7 @@
                DEVELOPMENT_TEAM = 5ZV937VB25;
                IBSC_MODULE = SnapKit;
                INFOPLIST_FILE = "Target Support Files/SnapKit/ResourceBundle-SnapKit_Privacy-SnapKit-Info.plist";
                IPHONEOS_DEPLOYMENT_TARGET = 10.0;
                IPHONEOS_DEPLOYMENT_TARGET = 12.0;
                PRODUCT_BUNDLE_IDENTIFIER = com.sinata.XQMuse.test;
                PRODUCT_NAME = SnapKit_Privacy;
                SDKROOT = iphoneos;
@@ -15506,7 +15506,7 @@
                DEVELOPMENT_TEAM = 5ZV937VB25;
                IBSC_MODULE = SnapKit;
                INFOPLIST_FILE = "Target Support Files/SnapKit/ResourceBundle-SnapKit_Privacy-SnapKit-Info.plist";
                IPHONEOS_DEPLOYMENT_TARGET = 10.0;
                IPHONEOS_DEPLOYMENT_TARGET = 12.0;
                PRODUCT_BUNDLE_IDENTIFIER = com.sinata.XQMuse.test;
                PRODUCT_NAME = SnapKit_Privacy;
                SDKROOT = iphoneos;
XQMuse.xcodeproj/project.pbxproj
@@ -60,6 +60,7 @@
        1327C6822C81D107005DA44B /* PlanGuide_3_VC.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1327C6802C81D107005DA44B /* PlanGuide_3_VC.swift */; };
        1327C6832C81D107005DA44B /* PlanGuide_3_VC.xib in Resources */ = {isa = PBXBuildFile; fileRef = 1327C6812C81D107005DA44B /* PlanGuide_3_VC.xib */; };
        132C40292C816003002E3270 /* SourceHanSerifCN-Medium.otf in Resources */ = {isa = PBXBuildFile; fileRef = 132C40282C816002002E3270 /* SourceHanSerifCN-Medium.otf */; };
        132C4B782CC0E63D00EA56AF /* WeChatTools.swift in Sources */ = {isa = PBXBuildFile; fileRef = 132C4B772CC0E63D00EA56AF /* WeChatTools.swift */; };
        132C7EF12C8FE3B900A4CA18 /* ChooseOptTitleView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 132C7EF02C8FE3B900A4CA18 /* ChooseOptTitleView.swift */; };
        132C7EF32C8FE3BF00A4CA18 /* ChooseOptTitleView.xib in Resources */ = {isa = PBXBuildFile; fileRef = 132C7EF22C8FE3BF00A4CA18 /* ChooseOptTitleView.xib */; };
        132C7EF72C8FE9BB00A4CA18 /* ChooseOptTitleTCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = 132C7EF62C8FE9BB00A4CA18 /* ChooseOptTitleTCell.xib */; };
@@ -361,6 +362,8 @@
        1327C6802C81D107005DA44B /* PlanGuide_3_VC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PlanGuide_3_VC.swift; sourceTree = "<group>"; };
        1327C6812C81D107005DA44B /* PlanGuide_3_VC.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = PlanGuide_3_VC.xib; sourceTree = "<group>"; };
        132C40282C816002002E3270 /* SourceHanSerifCN-Medium.otf */ = {isa = PBXFileReference; lastKnownFileType = file; path = "SourceHanSerifCN-Medium.otf"; sourceTree = "<group>"; };
        132C4B762CC0E5CA00EA56AF /* XQMuse-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "XQMuse-Bridging-Header.h"; sourceTree = "<group>"; };
        132C4B772CC0E63D00EA56AF /* WeChatTools.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WeChatTools.swift; sourceTree = "<group>"; };
        132C7EF02C8FE3B900A4CA18 /* ChooseOptTitleView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChooseOptTitleView.swift; sourceTree = "<group>"; };
        132C7EF22C8FE3BF00A4CA18 /* ChooseOptTitleView.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = ChooseOptTitleView.xib; sourceTree = "<group>"; };
        132C7EF52C8FE9BB00A4CA18 /* ChooseOptTitleTCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChooseOptTitleTCell.swift; sourceTree = "<group>"; };
@@ -714,6 +717,26 @@
            path = VC;
            sourceTree = "<group>";
        };
        132C4B792CC0EBDD00EA56AF /* Layouts */ = {
            isa = PBXGroup;
            children = (
                139C165F2C6A0FBB00A924D9 /* TestLeftRightCollectionViewFlowLayout.swift */,
                1336EFA42C6DEB550075E070 /* HoverHeaderFlowLayout.swift */,
                13897D882C7DB9D7006209E0 /* EqualCellSpaceFlowLayout.swift */,
            );
            path = Layouts;
            sourceTree = "<group>";
        };
        132C4B7A2CC0EBFA00EA56AF /* StoreKit */ = {
            isa = PBXGroup;
            children = (
                1304526E2CB4FF280049FB3A /* InPurchaseManager.swift */,
                130452692CB4CA310049FB3A /* XQMuseStoreKit.storekit */,
                1304526B2CB4CB210049FB3A /* StoreKitTestCertificate.cer */,
            );
            path = StoreKit;
            sourceTree = "<group>";
        };
        132C7EF42C8FE9A800A4CA18 /* TCell */ = {
            isa = PBXGroup;
            children = (
@@ -1058,18 +1081,16 @@
        13985DB32C69B7D40046B6DC /* Config */ = {
            isa = PBXGroup;
            children = (
                132C4B7A2CC0EBFA00EA56AF /* StoreKit */,
                132C4B792CC0EBDD00EA56AF /* Layouts */,
                132C4B772CC0E63D00EA56AF /* WeChatTools.swift */,
                13D2A0542CB671D9005F6014 /* SDK */,
                1304526E2CB4FF280049FB3A /* InPurchaseManager.swift */,
                130452692CB4CA310049FB3A /* XQMuseStoreKit.storekit */,
                1304526B2CB4CB210049FB3A /* StoreKitTestCertificate.cer */,
                13A0A8A02C746ADA00DF08B6 /* Enums */,
                139C165F2C6A0FBB00A924D9 /* TestLeftRightCollectionViewFlowLayout.swift */,
                1336EFA42C6DEB550075E070 /* HoverHeaderFlowLayout.swift */,
                137175C42C6C3C2100B38EF1 /* Fonts */,
                13985DB42C69B7DF0046B6DC /* Def.swift */,
                13985DB72C69B80D0046B6DC /* Themes.swift */,
                13897D882C7DB9D7006209E0 /* EqualCellSpaceFlowLayout.swift */,
                135B1D1F2C8863D10089A9BE /* Types.swift */,
                132C4B762CC0E5CA00EA56AF /* XQMuse-Bridging-Header.h */,
            );
            path = Config;
            sourceTree = "<group>";
@@ -1717,6 +1738,7 @@
                130913EF2C6DE67E00418201 /* HomeRelaxBanner_2_1_CCell.swift in Sources */,
                1333DC7A2C72D8C400D8ACAE /* CourseDetail_3_TCell.swift in Sources */,
                135C2A752C7F033300CC2A67 /* CLPlayerView.swift in Sources */,
                132C4B782CC0E63D00EA56AF /* WeChatTools.swift in Sources */,
                1300BD3C2C6DFB1C000BCA5E /* VIPCenterVC.swift in Sources */,
                134803D62C76E3E000F4FDDA /* WatchHistoryVC.swift in Sources */,
                13D2A0492CB670BF005F6014 /* OBSUploader.swift in Sources */,
@@ -1890,8 +1912,6 @@
                ENABLE_USER_SCRIPT_SANDBOXING = NO;
                FRAMEWORK_SEARCH_PATHS = (
                    "$(inherited)",
                    "$(PROJECT_DIR)/XQMuse/Config/SDK\\ 2",
                    "$(PROJECT_DIR)/XQMuse/Config/SDK\\ 2",
                    "$(PROJECT_DIR)/XQMuse/Config/SDK",
                );
                GENERATE_INFOPLIST_FILE = YES;
@@ -1914,7 +1934,8 @@
                MARKETING_VERSION = 1.0;
                OTHER_LDFLAGS = (
                    "$(inherited)",
                    "-l\"WechatOpenSDK\"",
                    "-ObjC",
                    "-\"WechatOpenSDK\"",
                    "-l\"c++\"",
                    "-l\"resolv\"",
                    "-l\"sqlite3.0\"",
@@ -2014,6 +2035,7 @@
                    "\"XCGLogger\"",
                    "-force_load",
                    "$(SRCROOT)/XQMuse/Config/SDK/OBS.framework/OBS",
                    "\"-ld64\"",
                );
                PRODUCT_BUNDLE_IDENTIFIER = com.sinata.XQMuse.test;
                PRODUCT_NAME = "$(TARGET_NAME)";
@@ -2023,6 +2045,7 @@
                SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO;
                SUPPORTS_XR_DESIGNED_FOR_IPHONE_IPAD = NO;
                SWIFT_EMIT_LOC_STRINGS = YES;
                SWIFT_OBJC_BRIDGING_HEADER = "/Users/yvkd/XiLaida/XQMuse/XQMuse/Config/XQMuse-Bridging-Header.h";
                SWIFT_VERSION = 5.0;
                TARGETED_DEVICE_FAMILY = 1;
            };
@@ -2043,8 +2066,6 @@
                ENABLE_USER_SCRIPT_SANDBOXING = NO;
                FRAMEWORK_SEARCH_PATHS = (
                    "$(inherited)",
                    "$(PROJECT_DIR)/XQMuse/Config/SDK\\ 2",
                    "$(PROJECT_DIR)/XQMuse/Config/SDK\\ 2",
                    "$(PROJECT_DIR)/XQMuse/Config/SDK",
                );
                GENERATE_INFOPLIST_FILE = YES;
@@ -2067,7 +2088,8 @@
                MARKETING_VERSION = 1.0;
                OTHER_LDFLAGS = (
                    "$(inherited)",
                    "-l\"WechatOpenSDK\"",
                    "-ObjC",
                    "-\"WechatOpenSDK\"",
                    "-l\"c++\"",
                    "-l\"resolv\"",
                    "-l\"sqlite3.0\"",
@@ -2167,6 +2189,7 @@
                    "\"XCGLogger\"",
                    "-force_load",
                    "$(SRCROOT)/XQMuse/Config/SDK/OBS.framework/OBS",
                    "\"-ld64\"",
                );
                PRODUCT_BUNDLE_IDENTIFIER = com.sinata.XQMuse.test;
                PRODUCT_NAME = "$(TARGET_NAME)";
@@ -2176,6 +2199,7 @@
                SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO;
                SUPPORTS_XR_DESIGNED_FOR_IPHONE_IPAD = NO;
                SWIFT_EMIT_LOC_STRINGS = YES;
                SWIFT_OBJC_BRIDGING_HEADER = "/Users/yvkd/XiLaida/XQMuse/XQMuse/Config/XQMuse-Bridging-Header.h";
                SWIFT_VERSION = 5.0;
                TARGETED_DEVICE_FAMILY = 1;
            };
XQMuse/AppDelegate.swift
@@ -9,19 +9,47 @@
@main
class AppDelegate: UIResponder, UIApplicationDelegate {
class AppDelegate: UIResponder, UIApplicationDelegate,WXApiDelegate{
                var window: UIWindow?
                func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
        WeChatTools.register(appid: WeChatAPPID, link: "https://app.xqzhihui.com/app/")
                                return true
                }
                func application(_ application: UIApplication, supportedInterfaceOrientationsFor window: UIWindow?) -> UIInterfaceOrientationMask {
                                return .allButUpsideDown
                }
    func application(_ application: UIApplication, continue userActivity: NSUserActivity, restorationHandler: @escaping ([any UIUserActivityRestoring]?) -> Void) -> Bool {
        return WXApi.handleOpenUniversalLink(userActivity, delegate: self)
    }
    func application(_ application: UIApplication, handleOpen url: URL) -> Bool {
        if url.scheme == WeChatAPPID{
            return WXApi.handleOpen(url, delegate: self)
        }
        return true
    }
    func application(_ application: UIApplication, open url: URL, sourceApplication: String?, annotation: Any) -> Bool {
        if url.scheme == WeChatAPPID{
            return WXApi.handleOpen(url, delegate: self)
        }
        return true
    }
    func application(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey : Any] = [:]) -> Bool {
        if url.scheme == WeChatAPPID{
            return WXApi.handleOpen(url, delegate: self)
        }
        return true
    }
                // MARK: UISceneSession Lifecycle
@@ -37,6 +65,15 @@
                                // Use this method to release any resources that were specific to the discarded scenes, as they will not return.
                }
    func onReq(_ req: BaseReq) {
}
    func onResp(_ resp: BaseResp) {
    }
}
XQMuse/Assets.xcassets/Btns/btn_share_1.imageset/btn_share@2x.png
Binary files differ
XQMuse/Assets.xcassets/Btns/btn_share_1.imageset/btn_share@3x.png
Binary files differ
XQMuse/Assets.xcassets/Placeholder/bg_guide_home.imageset/Contents.json
New file
@@ -0,0 +1,22 @@
{
  "images" : [
    {
      "idiom" : "universal",
      "scale" : "1x"
    },
    {
      "filename" : "组 20@2x.png",
      "idiom" : "universal",
      "scale" : "2x"
    },
    {
      "filename" : "组 20@3x.png",
      "idiom" : "universal",
      "scale" : "3x"
    }
  ],
  "info" : {
    "author" : "xcode",
    "version" : 1
  }
}
XQMuse/Assets.xcassets/Placeholder/bg_guide_home.imageset/组 20@2x.png
XQMuse/Assets.xcassets/Placeholder/bg_guide_home.imageset/组 20@3x.png
XQMuse/Base/BaseNav.swift
@@ -12,7 +12,7 @@
                /// 需要透明Nav的VC
                private var lucencyVCs = [LoginVC.self]
                private var whiteStyleVCs = [HomeItemDetailVC.self,CourseDetialVC.self,HomeItemDetailVC.self,CourseDetialVideoVC.self,PavilionDetailVC.self]
                private var whiteStyleVCs = [HomeItemDetailVC.self,CourseDetialVC.self,CourseDetialVideoVC.self,PavilionDetailVC.self]
                open override func viewDidLoad() {
                                super.viewDidLoad()
XQMuse/Config/Def.swift
@@ -12,7 +12,8 @@
import QMUIKit
import OSLog
//https://dummyimage.com/100x100
let WeChatAPPID = "wx4b9c1d814c2902a3"
let WeChatSecrect = "60fed4b6f52603ba6769e1118b4a57ae"
let app = UIApplication.shared.delegate as! AppDelegate
XQMuse/Config/EqualCellSpaceFlowLayout.swift
File was deleted
XQMuse/Config/Layouts/HoverHeaderFlowLayout.swift
New file
@@ -0,0 +1,99 @@
//
//  HoverHeaderFlowLayout.swift
//  XQMuse
//
//  Created by 无故事王国 on 2024/8/15.
//
import Foundation
import UIKit
import JQTools
/// 悬浮HeaderView
class HoverHeaderFlowLayout:UICollectionViewFlowLayout{
                var naviHeight:CGFloat = JQ_NavBarHeight//默认分组停放高度
                override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? {
                                //UICollectionViewLayoutAttributes:我称它为collectionView中的item(包括cell和header、footer这些)的结构信息
                                //截取到父类所返回的数组(里面放的是当前屏幕所能展示的item的结构信息),并转化成不可变数组
                                var superArray = super.layoutAttributesForElements(in: rect)
                                //创建存索引的数组,无符号(正整数),无序(不能通过下标取值),不可重复(重复的话会自动过滤)
                                let noneHeaderSections=NSMutableIndexSet();
                                for  attributes:UICollectionViewLayoutAttributes in superArray! {
                                                //如果当前的元素分类是一个cell,将cell所在的分区section加入数组,重复的话会自动过滤
                                                if attributes.representedElementCategory == .cell{
                                                                noneHeaderSections.add(attributes.indexPath.section)
                                                }
                                }
                                //遍历superArray,将当前屏幕中拥有的header的section从数组中移除,得到一个当前屏幕中没有header的section数组
                                //正常情况下,随着手指往上移,header脱离屏幕会被系统回收而cell尚在,也会触发该方法
                                for attributes:UICollectionViewLayoutAttributes in superArray! {
                                                //如果当前的元素是一个header,将header所在的section从数组中移除
                                                if attributes.representedElementKind == UICollectionView.elementKindSectionHeader {
                                                                noneHeaderSections.remove(attributes.indexPath.section)
                                                }
                                }
                                //遍历当前屏幕中没有header的section数组
                                noneHeaderSections .enumerate({ (idx, obj) -> Void in
                                                //取到当前section中第一个item的indexPath
                                                let indexPath = NSIndexPath(item: 0, section: idx)
                                                let attributes=self.layoutAttributesForSupplementaryView(ofKind: UICollectionView.elementKindSectionHeader, at: indexPath as IndexPath)
                                                //如果当前分区确实有因为离开屏幕而被系统回收的header
                                                if attributes != nil {
                                                                //将该header结构信息重新加入到superArray中去
                                                                superArray?.append(attributes!)
                                                }
                                })
                                //遍历superArray,改变header结构信息中的参数,使它可以在当前section还没完全离开屏幕的时候一直显示
                                for  attributes:UICollectionViewLayoutAttributes in superArray! {
                                                //如果当前item是header
                                                if attributes.representedElementKind == UICollectionView.elementKindSectionHeader {
                                                                //得到当前header所在分区的cell的数量
                                                                let numberOfItemsInSection=self.collectionView!.numberOfItems(inSection: attributes.indexPath.section)
                                                                //取到当前section中第一个item的indexPath
                                                                let firstItemIndexPath = NSIndexPath(item: 0, section: attributes.indexPath.section)
                                                                //得到最后一个item的indexPath
                                                                let lastItemIndexPath = NSIndexPath(item: max(0, numberOfItemsInSection-1), section: attributes.indexPath.section)
                                                                //得到第一个item和最后一个item的结构信息
                                                                var firstItemAttributes, lastItemAttributes:UICollectionViewLayoutAttributes
                                                                if numberOfItemsInSection>0 {
                                                                                //cell有值,则获取第一个cell和最后一个cell的结构信息
                                                                                firstItemAttributes=self.layoutAttributesForItem(at: firstItemIndexPath as IndexPath)!
                                                                                lastItemAttributes=self.layoutAttributesForItem(at: lastItemIndexPath as IndexPath)!
                                                                }else{
                                                                                //cell没值,就新建一个UICollectionViewLayoutAttributes
                                                                                firstItemAttributes=UICollectionViewLayoutAttributes()
                                                                                //然后模拟出在当前分区中的唯一一个cell,cell在header的下面,高度为0,还与header隔着可能存在的sectionInset的top
                                                                                let y=attributes.frame.maxY + sectionInset.top
                                                                                firstItemAttributes.frame=CGRect(x: 0, y: y, width: 0, height: 0)
                                                                                //因为只有一个cell,所以最后一个cell等于第一个cell
                                                                                lastItemAttributes=firstItemAttributes;
                                                                }
                                                                //获取当前header的frame
                                                                var rect=attributes.frame;
                                                                //当前的滑动距离 + 因为导航栏产生的偏移量,默认为0(如果app需求不同,需自己设置)
                                                                let offset=(self.collectionView?.contentOffset.y)! + naviHeight
                                                                //第一个cell的y值 - 当前header的高度 - 可能存在的sectionInset的top
                                                                let headerY=firstItemAttributes.frame.origin.y-rect.size.height-sectionInset.top
                                                                //哪个大取哪个,保证header悬停
                                                                //针对当前header基本上都是offset更加大,针对下一个header则会是headerY大,各自处理
                                                                let maxY=max(offset, headerY)
                                                                //最后一个cell的y值 + 最后一个cell的高度 + 可能存在的sectionInset的bottom - 当前header的高度
                                                                //当当前section的footer或者下一个section的header接触到当前header的底部,计算出的headerMissingY即为有效值
                                                                let headerMissingY = lastItemAttributes.frame.maxY + sectionInset.bottom - rect.size.height;
                                                                //给rect的y赋新值,因为在最后消失的临界点要跟谁消失,所以取小
                                                                rect.origin.y=min(maxY, headerMissingY)
                                                                //给header的结构信息的frame重新赋值
                                                                attributes.frame=rect
                                                                //如果按照正常情况下,header离开屏幕被系统回收,而header的层次关系又与cell相等,如果不去理会,会出现cell在header上面的情况
                                                                //通过打印可以知道cell的层次关系zIndex数值为0,我们可以将header的zIndex设置成1,如果不放心,也可以将它设置成非常大,这里随便填了个7
                                                                attributes.zIndex=7
                                                }
                                }
                                return superArray
                }
                //return true;表示一旦滑动就实时调用上面这个layoutAttributesForElementsInRect:方法
                override func shouldInvalidateLayout(forBoundsChange newBounds: CGRect) -> Bool {
                                return true
                }
}
XQMuse/Config/StoreKit/InPurchaseManager.swift
New file
@@ -0,0 +1,305 @@
//
//  StoreTransaction.swift
//  ExplorerProject
//
//  Created by 无故事王国 on 2024/4/1.
//  Copyright © 2024 younger_times. All rights reserved.
//
import SwiftyStoreKit
import StoreKit
import HandyJSON
struct PurchaseModel:HandyJSON{
    var environment: String?
    var receipt:PurchaseReceiptModel?
    var status: Int = 0
}
struct PurchaseReceiptModel:HandyJSON{
    var adam_id: Int = 0
    var app_item_id: Int = 0
    var application_version: Int = 0
    var bundle_id: String?
    var download_id: Int = 0
    var in_app = [PurchageInAppModel]()
    var original_application_version: String?
    var original_purchase_date: String?
    var original_purchase_date_ms: Int = 0
    var original_purchase_date_pst: String?
    var receipt_creation_date: String?
    var receipt_creation_date_ms: Int = 0
    var receipt_creation_date_pst: String?
    var receipt_type: String?
    var request_date: String?
    var request_date_ms: Int = 0
    var request_date_pst: String?
    var version_external_identifier: Int = 0
}
struct PurchageInAppModel:HandyJSON{
}
struct PurchaseResultModel:HandyJSON{
    var environment: String?
    var receipt: PurchaseReceipt?
    var status: Int = 0
}
struct PurchaseReceipt:HandyJSON{
    var adam_id: Int = 0
    var app_item_id: Int = 0
    var application_version: String?
    var bundle_id: String?
    var download_id: Int = 0
    var in_app = [PurchaseInAPP]()
    var original_application_version: String?
    var original_purchase_date: String?
    var original_purchase_date_ms: String?
    var original_purchase_date_pst: String?
    var receipt_creation_date: String?
    var receipt_creation_date_ms: String?
    var receipt_creation_date_pst: String?
    var receipt_type: String?
    var request_date: String?
    var request_date_ms: String?
    var request_date_pst: String?
    var version_external_identifier: Int = 0
}
struct PurchaseInAPP:HandyJSON{
    var in_app_ownership_type: String?
    var is_trial_period: String?
    var original_purchase_date: String?
    var original_purchase_date_ms: String?
    var original_purchase_date_pst: String?
    var original_transaction_id: String?
    var product_id: String?
    var purchase_date: String?
    var purchase_date_ms: String?
    var purchase_date_pst: String?
    var quantity: String?
    var transaction_id: String?
}
class InPurchaseManager:NSObject{
    private static var _sharedInstance: InPurchaseManager!
    private var productList = Set<String>()
    private(set) var products = Set<SKProduct>()
    @discardableResult
    public class func instance() -> InPurchaseManager {
        guard let instance = _sharedInstance else {
            _sharedInstance = InPurchaseManager()
            return _sharedInstance!
        }
        return instance
    }
    func setProductList(_ list:Set<String>,clouse:@escaping (Set<SKProduct>)->Void){
        productList = list
        SwiftyStoreKit.retrieveProductsInfo(list) { result in
            if result.retrievedProducts.count > 0 {
                InPurchaseManager._sharedInstance.products = result.retrievedProducts
                clouse(result.retrievedProducts)
            }
        }
    }
    func getIPAPrice(_ price:Int,clouse:@escaping (SKProduct)->Void){
        var ipaId = ""
        switch price {
            case 98: ipaId = "com.jkfitness.a.price.1"
            case 298:ipaId = "com.jkfitness.a.price.2"
            case 488:ipaId = "com.jkfitness.a.price.3"
            case 698:ipaId = "com.jkfitness.a.price.4"
            case 998:ipaId = "com.jkfitness.a.price.5"
            default:break
        }
        var productIds = Set<String>()
        productIds.insert(ipaId)
        InPurchaseManager.instance().setProductList(productIds) {products in
            if let product = products.first{
                clouse(product)
            }
        }
    }
    func dismiss(){
        InPurchaseManager._sharedInstance = nil
    }
    /// 购买
    /// - Parameters:
    ///   - ID: ID值
    ///   - quantity: 购买数量
    ///   - applicationUsername: 购买用户名的唯一标识
    class func purchaseProduct(ID:String,quantity:Int = 1,applicationUsername:String, completion: @escaping ( PurchaseResultModel) -> Void,errorClouse:@escaping (Error)->Void){
        var purcahseProduct:SKProduct?
        for product in _sharedInstance.products {
            if product.productIdentifier == ID{
                purcahseProduct = product;break
            }
        }
        guard let product = purcahseProduct else {return}
        var inSanbox:Bool = false
#if DEBUG
        inSanbox = true
#endif
        SwiftyStoreKit.completeTransactions { purchases in
            if let product = purchases.first{
                switch product.transaction.transactionState {
                    case .purchased:
                        alertSuccess(msg: "完成购买")
                    case .purchasing:
                        showHUD("购买中")
                    case .failed:
                        alertError(msg: "购买失败")
                    case .restored:
                        alertSuccess(msg: "恢复购买")
                    default:break
                }
            }
        }
        SwiftyStoreKit.purchaseProduct(product, quantity: quantity, atomically: true, applicationUsername: applicationUsername, simulatesAskToBuyInSandbox: false, paymentDiscount: nil) { result in
            switch result {
                case .success(let purchase):
                    var type:AppleReceiptValidator.VerifyReceiptURLType = .production
                    if inSanbox{
                        type = .sandbox
                    }
                    var recepit = AppleReceiptValidator(service: type, sharedSecret: nil)
                    SwiftyStoreKit.verifyReceipt(using: recepit) { result in
                        switch result {
                            case .success(let receipt):
                                if let  model = PurchaseResultModel.deserialize(from: receipt){
                                    completion(model)
                                }
                                break
                            case .error(let error):
                                errorClouse(error)
                                //                                                                                                                                print(error.localizedDescription)
                        }
                    }
                case .error(let error):
                    //                                                                                print(error.localizedDescription)
                    errorClouse(error)
            }
        }
    }
    /// 恢复购买
    class func resotrePurchase(applicationUsername:String, completion: @escaping ( PurchaseResultModel) -> Void,errorClouse:@escaping (Error)->Void){
        SwiftyStoreKit.completeTransactions { purchases in
            if let product = purchases.first{
                switch product.transaction.transactionState {
                    case .purchased:
                        alertSuccess(msg: "完成购买")
                    case .purchasing:
                        showHUD("购买中")
                    case .failed:
                        alertError(msg: "购买失败")
                    case .restored:
                        alertSuccess(msg: "恢复购买")
                    default:break
                }
            }
        }
        SwiftyStoreKit.restorePurchases(atomically: true, applicationUsername: applicationUsername) { result in
            if result.restoreFailedPurchases.count > 0 {
                //恢复失败
                print("restore Failed:\(result.restoredPurchases)")
            }else if result.restoredPurchases.count > 0 {
                print("restore Success")
                var inSanbox:Bool = false
#if DEBUG
                inSanbox = true
#endif
                var type:AppleReceiptValidator.VerifyReceiptURLType = .production
                if inSanbox{
                    type = .sandbox
                }
                let recepit = AppleReceiptValidator(service: type, sharedSecret: nil)
                SwiftyStoreKit.verifyReceipt(using: recepit) { result in
                    switch result {
                        case .success(let receipt):
                            if let  model = PurchaseResultModel.deserialize(from: receipt){
                                completion(model)
                            }
                            break
                        case .error(let error):
                            errorClouse(error)
                    }
                }
            }else{
                print("Nothing to Restore")
            }
        }
    }
    //获取APP 首次安装时间
    func test1(){
        let queue = DispatchQueue(label: "inapppurchasequeue")
        queue.async {
            let receiptURL = Bundle.main.appStoreReceiptURL
            guard receiptURL?.path != nil else { return }
            do {
                let receiptData = try Data(contentsOf: receiptURL!, options: .alwaysMapped)
                let base64EncodedReceipt = receiptData.base64EncodedString(options: [])
                var verifyReceipt:String = AppleReceiptValidator.VerifyReceiptURLType.sandbox.rawValue
#if !DEBUG
                verifyReceipt = AppleReceiptValidator.VerifyReceiptURLType.production.rawValue
#endif
                let purchaseURL = URL(string: verifyReceipt)!
                var request = URLRequest(url: purchaseURL)
                request.httpMethod = "POST"
                request.setValue("application/json", forHTTPHeaderField: "Content-Type")
                let jsonBody: [String: Any] = [
                    "receipt-data": base64EncodedReceipt,
                    "password": ShareAppleKey // 你的共享密钥
                ]
                let jsonData = try JSONSerialization.data(withJSONObject: jsonBody, options: [])
                request.httpBody = jsonData
                let session = URLSession.shared
                let task = session.dataTask(with: request) { (data, response, error) in
                    if let error = error {return}
                    guard let data = data else { return }
                    do {
                        if let json = try JSONSerialization.jsonObject(with: data, options: []) as? [String: Any] {
                            print(json)
                            if let purchageModel = PurchaseModel.deserialize(from: json),purchageModel.status == 0{
                            }
                        }
                    } catch {
                        print("JSON processing failed: \(error)")
                    }
                }
                task.resume()
            } catch {
                print("Error reading receipt data: \(error)")
            }
        }
    }
}
XQMuse/Config/StoreKit/XQMuseStoreKit.storekit
New file
@@ -0,0 +1,247 @@
{
  "appPolicies" : {
    "eula" : "",
    "policies" : [
      {
        "locale" : "en_US",
        "policyText" : "",
        "policyURL" : ""
      }
    ]
  },
  "identifier" : "3D29D5F7",
  "nonRenewingSubscriptions" : [
    {
      "displayPrice" : "299",
      "familyShareable" : false,
      "internalID" : "7BDE4968",
      "localizations" : [
        {
          "description" : "购买一个月会员",
          "displayName" : "一个月会员",
          "locale" : "zh_CN"
        }
      ],
      "productID" : "com.XQMuse.VIP.month.0",
      "referenceName" : "购买一个月会员",
      "type" : "NonRenewingSubscription"
    },
    {
      "displayPrice" : "499",
      "familyShareable" : false,
      "internalID" : "DDDE321B",
      "localizations" : [
        {
          "description" : "购买6个月会员",
          "displayName" : "半年会员",
          "locale" : "zh_CN"
        }
      ],
      "productID" : "com.XQMuse.VIP.semester.0",
      "referenceName" : "购买半年会员",
      "type" : "NonRenewingSubscription"
    },
    {
      "displayPrice" : "499",
      "familyShareable" : false,
      "internalID" : "436E2DBE",
      "localizations" : [
        {
          "description" : "购买12个月会员",
          "displayName" : "年度会员",
          "locale" : "zh_CN"
        }
      ],
      "productID" : "com.XQMuse.VIP.year.0",
      "referenceName" : "购买年度会员",
      "type" : "NonRenewingSubscription"
    }
  ],
  "products" : [
    {
      "displayPrice" : "0.99",
      "familyShareable" : false,
      "internalID" : "521CE106",
      "localizations" : [
        {
          "description" : "购买10颗疗愈币",
          "displayName" : "10币",
          "locale" : "zh_CN"
        }
      ],
      "productID" : "com.XQMuse.p.0",
      "referenceName" : "充值10疗愈币",
      "type" : "Consumable"
    },
    {
      "displayPrice" : "1.99",
      "familyShareable" : false,
      "internalID" : "E7DC523B",
      "localizations" : [
        {
          "description" : "购买20颗疗愈币",
          "displayName" : "20币",
          "locale" : "zh_CN"
        }
      ],
      "productID" : "com.XQMuse.p.1",
      "referenceName" : "充值20疗愈币",
      "type" : "Consumable"
    },
    {
      "displayPrice" : "2.99",
      "familyShareable" : false,
      "internalID" : "6AD670BC",
      "localizations" : [
        {
          "description" : "购买50颗疗愈币",
          "displayName" : "50币",
          "locale" : "zh_CN"
        }
      ],
      "productID" : "com.XQMuse.p.2",
      "referenceName" : "充值50疗愈币",
      "type" : "Consumable"
    },
    {
      "displayPrice" : "3.99",
      "familyShareable" : false,
      "internalID" : "C8E195D0",
      "localizations" : [
        {
          "description" : "购买100颗疗愈币",
          "displayName" : "100币",
          "locale" : "zh_CN"
        }
      ],
      "productID" : "com.XQMuse.p.3",
      "referenceName" : "充值100疗愈币",
      "type" : "Consumable"
    }
  ],
  "settings" : {
    "_billingGracePeriodEnabled" : true,
    "_failTransactionsEnabled" : false,
    "_locale" : "zh_CN",
    "_storefront" : "CHN",
    "_storeKitErrors" : [
      {
        "current" : null,
        "enabled" : false,
        "name" : "Load Products"
      },
      {
        "current" : null,
        "enabled" : false,
        "name" : "Purchase"
      },
      {
        "current" : null,
        "enabled" : false,
        "name" : "Verification"
      },
      {
        "current" : {
          "index" : 2,
          "type" : "generic"
        },
        "enabled" : false,
        "name" : "App Store Sync"
      },
      {
        "current" : null,
        "enabled" : false,
        "name" : "Subscription Status"
      },
      {
        "current" : {
          "index" : 3,
          "type" : "generic"
        },
        "enabled" : false,
        "name" : "App Transaction"
      },
      {
        "current" : null,
        "enabled" : false,
        "name" : "Manage Subscriptions Sheet"
      },
      {
        "current" : null,
        "enabled" : false,
        "name" : "Refund Request Sheet"
      },
      {
        "current" : null,
        "enabled" : false,
        "name" : "Offer Code Redeem Sheet"
      }
    ]
  },
  "subscriptionGroups" : [
    {
      "id" : "1B73E9E9",
      "localizations" : [
      ],
      "name" : "Years",
      "subscriptions" : [
        {
          "adHocOffers" : [
            {
              "internalID" : "B4ECD233",
              "offerID" : "LAJ234QMZ5801AAC",
              "paymentMode" : "free",
              "referenceName" : "促销码",
              "subscriptionPeriod" : "P1Y"
            }
          ],
          "codeOffers" : [
            {
              "displayPrice" : "200",
              "eligibility" : [
                "existing",
                "expired",
                "new"
              ],
              "internalID" : "F62AF748",
              "isStackable" : true,
              "paymentMode" : "payUpFront",
              "referenceName" : "促销",
              "subscriptionPeriod" : "P6M"
            }
          ],
          "displayPrice" : "149",
          "familyShareable" : false,
          "groupNumber" : 1,
          "internalID" : "D8314451",
          "introductoryOffer" : {
            "displayPrice" : "0.99",
            "internalID" : "89D5DFC5",
            "paymentMode" : "free",
            "subscriptionPeriod" : "P3D"
          },
          "localizations" : [
            {
              "description" : "包年",
              "displayName" : "包年年度会员",
              "locale" : "zh_CN"
            }
          ],
          "productID" : "com.XQMuse.VIP.year.renewing.0",
          "recurringSubscriptionPeriod" : "P1Y",
          "referenceName" : "购买年度会员(持续订阅)",
          "subscriptionGroupID" : "1B73E9E9",
          "type" : "RecurringSubscription",
          "winbackOffers" : [
          ]
        }
      ]
    }
  ],
  "version" : {
    "major" : 4,
    "minor" : 0
  }
}
XQMuse/Config/WeChatTools.swift
New file
@@ -0,0 +1,205 @@
//
//  WeChatTools.swift
//  WanPai
//
//  Created by 无故事王国 on 2023/9/26.
//
import Foundation
import HandyJSON
typealias WeachatClosure = (WechatModel?)->(Void)
typealias WechatUserClosure = (WechatUserInfoModel?)->(Void)
struct WechatModel:HandyJSON{
                var access_token = ""
                var expires_in = 0
                var openid = ""
                var refresh_token = ""
                var scope = ""
                var unionid = ""
}
struct WechatUserInfoModel:HandyJSON{
                var openid = ""
                var nickname = ""
                var sex = 1
                var province = ""
                var city = ""
                var country = ""
                var headimgurl = ""
                var privilege = ""
                var unionid = ""
}
class WeChatTools{
                static func register(appid:String,link:String){
                                WXApi.registerApp(appid, universalLink: link)
                }
                /// 授权登录
                static func sendAuthRequest(){
                                let sendAuthReq = SendAuthReq()
                                sendAuthReq.scope = "snsapi_userinfo"
                                sendAuthReq.state = "XQMuse_iOS"
                                WXApi.send(sendAuthReq)
                }
                /// 完成授权登录,获取token
                static func getAccessToken(_ resp:SendAuthResp, loginInfo:WeachatClosure?){
                                guard resp.code != nil else {
                                                return
                                }
                                let url = "https://api.weixin.qq.com/sns/oauth2/access_token?appid=\(WeChatAPPID)&secret=\(WeChatSecrect)&code=\(resp.code!)&grant_type=authorization_code"
                                let Url = URL(string: url)
                                let session = URLSession.shared
                                let task = session.dataTask(with: Url!) { (data, response, error) in
                                                if error != nil{
                                                                return
                                                }
                                                do{
                                                                if let dataAsJSON = try JSONSerialization.jsonObject(with: data!) as? Dictionary<String, Any>{
                                                                                let model = WechatModel.deserialize(from: dataAsJSON)
                                                                                loginInfo?(model)
                                                                }else{
                                                                                loginInfo?(nil)
                                                                }
                                                }catch{
                                                                loginInfo?(nil)
                                                }
                                }
                                task.resume()
                }
                /// 获取用资料
                static func getUserInfo(access_token:String,openId:String,userInfo:WechatUserClosure?){
                                guard !access_token.isEmpty else {
                                                return
                                }
                                guard !openId.isEmpty else {
                                                return
                                }
                                let url = "https://api.weixin.qq.com/sns/userinfo?access_token=\(access_token)&openid=\(openId)"
                                let Url = URL(string: url)
                                let session = URLSession.shared
                                let task = session.dataTask(with: Url!) { (data, response, error) in
                                                if error != nil{
                                                                return
                                                }
                                                do{
                                                                if let dataAsJSON = try JSONSerialization.jsonObject(with: data!) as? Dictionary<String, Any>{
                                                                                let model = WechatUserInfoModel.deserialize(from: dataAsJSON)
                                                                                userInfo?(model)
                                                                }else{
                                                                                userInfo?(nil)
                                                                }
                                                }catch{
                                                                userInfo?(nil)
                                                }
                                }
                                task.resume()
                }
                /// 分享文本
                static func shareText(_ text:String,scene:WXScene = WXSceneSession){
                                let req = SendMessageToWXReq()
                                req.bText = true
                                req.text = text
                                req.scene = Int32(scene.rawValue)
                                WXApi.send(req)
                }
                /// 分享图片
                static func sharePic(_ img:UIImage,thumb:UIImage,scale:CGFloat = 0.6,scene:WXScene = WXSceneTimeline){
                                let imageObject = WXImageObject()
                                imageObject.imageData = img.jpegData(compressionQuality: scale)!
                                let mediaMessage = WXMediaMessage()
                                mediaMessage.thumbData = thumb.jpegData(compressionQuality: scale)
                                mediaMessage.mediaObject = imageObject
                                let req = SendMessageToWXReq()
                                req.bText = false
                                req.message = mediaMessage
                                req.scene = Int32(scene.rawValue)
                                WXApi.send(req)
                }
                /// 分享音乐
                static func shareMusic(_ musicUrl:String,musicLowBandUrl:String,title:String,desc:String,thumb:UIImage,scene:WXScene = WXSceneSession){
                                let musicObject = WXMusicObject()
                                musicObject.musicUrl = musicUrl
                                musicObject.musicLowBandUrl = musicLowBandUrl
                                let mediaMessage  = WXMediaMessage()
                                mediaMessage.title = title
                                mediaMessage.description = desc
                                mediaMessage.setThumbImage(thumb)
                                mediaMessage.mediaObject = musicObject
                                let req = SendMessageToWXReq()
                                req.bText = false
                                req.message = mediaMessage
                                req.scene = Int32(scene.rawValue)
                                WXApi.send(req)
                }
                /// 分享音乐
                static func shareMusic(_ musicData:String,musicLowBandData:String,title:String,desc:String,thumb:UIImage,scene:WXScene = WXSceneSession){
                                let musicObject = WXMusicObject()
                                musicObject.musicDataUrl = musicData
                                musicObject.musicLowBandUrl = musicLowBandData
                                let mediaMessage  = WXMediaMessage()
                                mediaMessage.title = title
                                mediaMessage.description = desc
                                mediaMessage.setThumbImage(thumb)
                                mediaMessage.mediaObject = musicObject
                                let req = SendMessageToWXReq()
                                req.bText = false
                                req.message = mediaMessage
                                req.scene = Int32(scene.rawValue)
                                WXApi.send(req)
                }
                static func shareUrl(_ url:String,title:String,desc:String,thumb:UIImage,scene:WXScene = WXSceneSession){
                                let webpageObject  = WXWebpageObject()
                                webpageObject.webpageUrl = url
                                let mediaMessage  = WXMediaMessage()
                                mediaMessage.title = title
                                mediaMessage.description = desc
                                mediaMessage.setThumbImage(thumb)
                                mediaMessage.mediaObject = webpageObject
                                let req = SendMessageToWXReq()
                                req.bText = false
                                req.message = mediaMessage
                                req.scene = Int32(scene.rawValue)
                                WXApi.send(req)
                }
                static func shareVideo(_ url:String,videoLowBandUrl:String,title:String,desc:String,thumb:UIImage, scene:WXScene = WXSceneSession){
                                let videoObject = WXVideoObject()
                                videoObject.videoUrl = url
                                videoObject.videoLowBandUrl = videoLowBandUrl
                                let mediaMessage  = WXMediaMessage()
                                mediaMessage.title = title
                                mediaMessage.description = desc
                                mediaMessage.setThumbImage(thumb)
                                mediaMessage.mediaObject = videoObject
                                let req = SendMessageToWXReq()
                                req.bText = false
                                req.message = mediaMessage
                                req.scene = Int32(scene.rawValue)
                                WXApi.send(req)
                }
}
XQMuse/Config/XQMuse-Bridging-Header.h
New file
@@ -0,0 +1,12 @@
//
//  XQMuse-Bridging-Header.h
//  XQMuse
//
//  Created by 无故事王国 on 2024/10/17.
//
#ifndef XQMuse_Bridging_Header_h
#define XQMuse_Bridging_Header_h
#import "WXApi.h"
#endif /* XQMuse_Bridging_Header_h */
XQMuse/Info.plist
@@ -2,6 +2,27 @@
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>CFBundleAllowMixedLocalizations</key>
    <true/>
    <key>CFBundleURLTypes</key>
    <array>
        <dict>
            <key>CFBundleTypeRole</key>
            <string>Editor</string>
            <key>CFBundleURLSchemes</key>
            <array>
                <string>wx4b9c1d814c2902a3</string>
            </array>
        </dict>
    </array>
    <key>LSApplicationQueriesSchemes</key>
    <array>
        <string>weixin</string>
        <string>weixinULAPI</string>
        <string>weixinURLParamsAPI</string>
    </array>
    <key>Localization native development region</key>
    <string>China</string>
    <key>NSAppTransportSecurity</key>
    <dict>
        <key>NSAllowsArbitraryLoads</key>
XQMuse/Root/Course/CCell/CourseOfficalCommendTopCCell.swift
@@ -33,7 +33,11 @@
                func setBanners(_ items:[CommonBannerModel]){
                                bannerModels = items
                                view_bannerContentView.setItems(items: items)
        view_bannerContentView.setItems(items: items) { m in
            if let id = m.courseId?.int{
                JQ_currentNavigationController().pushViewController(CourseDetialVC(courseId: id))
            }
        }
                }
                func clickAtClouse(_ clouse:@escaping (Int)->Void){
XQMuse/Root/Course/CourseVC.swift
@@ -111,7 +111,7 @@
                @objc func searchAction(){
                                let vc = SearchVC()
        let vc = SearchVC(serchType: .course)
                                push(vc: vc)
                }
XQMuse/Root/Course/VC/CourseDetialVC.swift
@@ -20,6 +20,7 @@
class CourseDetialVC: BaseVC {
                private var tableView:UITableView?
    private var collect_bitem:UIBarButtonItem!
                private let studyBtn = QMUIButton(type: .custom)
                private var headerView = CourseDetailHeaderView.jq_loadNibView()
                private var barStyle:UIStatusBarStyle = .lightContent
@@ -118,7 +119,12 @@
                                                self.tableView!.tableHeaderView = self.headerView
                                }
                                setFootView()
        collect_bitem = UIBarButtonItem(image: UIImage(named: "btn_collect"), style: .plain, target: self, action: #selector(collectionAction))
        collect_bitem.tintColor = .white
        let share_bitem = UIBarButtonItem(image: UIImage(named: "btn_share"), style: .plain, target: self, action: #selector(shareAction))
        share_bitem.tintColor = .white
        share_bitem.imageInsets = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 15)
        navigationItem.rightBarButtonItems = [share_bitem,collect_bitem]
                }
                private func getData(){
@@ -129,7 +135,15 @@
                                                                self.section1TCell.setItems(m)
                                                                self.section2TCell.setItems(m.list2)
                                                                if m.isBuy != .yes{
                //是否需要购买
                var  needPayment:Bool = true
                switch m.chargeType{
                    case .free:needPayment = false
                    case .payment:needPayment = !(m.isBuy == .yes)
                    case .vipFree:needPayment = !(UserViewModel.getAvatarInfo().isVip == .yes)
                }
                if needPayment{
                                                                                let attribute    = AttributedStringbuilder.build().add(string: "    疗愈币", withFont: .systemFont(ofSize: 12,weight: .bold), withColor: UIColor(hexString: "#F6F6F6")!).add(string: "\(m.generalPrice.jq_formatFloat)", withFont: .systemFont(ofSize: 21.71, weight: .bold), withColor: UIColor(hexString: "#F6F6F6")!).add(string: "  立即购买     ", withFont: .systemFont(ofSize: 16, weight: .bold), withColor: UIColor(hexString: "#F6F6F6")!).mutableAttributedString
                                                                                self.studyBtn.setAttributedTitle(attribute, for: .normal)
                                                                }
@@ -142,6 +156,7 @@
                                                                                self.pageMenu.setItems(["简介"], selectedItemIndex: 0)
                                                                }
                                                                self.tableView?.reloadData()
                self.setFootView()
                                                }
                                }).disposed(by: disposeBag)
                }
@@ -155,6 +170,7 @@
                                                make.height.equalTo(84)
                                }
        if courseDetailModel?.chargeType == .payment{
                                let giftBtn = QMUIButton(type: .custom)
                                giftBtn.imagePosition = .left
                                giftBtn.spacingBetweenImageAndTitle = 7.5
@@ -168,6 +184,7 @@
                                                make.left.equalTo(26)
                                                make.top.equalTo(26.5)
                                }
        }
                                studyBtn.setTitleColor(UIColor.white, for: .normal)
                                studyBtn.setTitle("    立即学习    ", for: .normal)
@@ -178,7 +195,7 @@
                                footView.addSubview(studyBtn)
                                studyBtn.snp.makeConstraints { make in
                                                make.right.equalTo(-20)
                                                make.centerY.equalTo(giftBtn)
            make.top.equalTo(22)
                                                make.height.equalTo(34)
                                }
                }
@@ -203,10 +220,32 @@
                                }).disposed(by: disposeBag)
                }
    @objc func collectionAction(){
        Services.meditationFavorite(id: courseId).subscribe(onNext: {data in
            self.courseDetailModel?.isCollect.troggle()
            if self.courseDetailModel?.isCollect == .yes{
                alertSuccess(msg: "收藏成功")
                self.collect_bitem.image = UIImage(named: "btn_collect_1_s")
                self.collect_bitem.tintColor = UIColor(hexString: "fe5b60")
            }else{
                alertSuccess(msg: "已取消收藏")
                self.collect_bitem.image = UIImage(named: "btn_collect")
                self.collect_bitem.tintColor = .white
            }
        }).disposed(by: disposeBag)
    }
    @objc func shareAction(){
        ShareView.show()
    }
                @objc func handleAction(_ btn:QMUIButton){
                                if let m = courseDetailModel{
                                                if m.chargeType == .free || (m.chargeType == .vipFree && UserViewModel.getAvatarInfo().isVip == .yes) || (m.chargeType == .payment && m.isBuy == .yes){
                guard m.list.count != 0 else {
                    alertError(msg: "课程目录异常");return
                }
                                                                let vc = CourseDetialVideoVC(items: m.list, selectIndex: IndexPath(row: 0, section: 0))
                                                                push(vc: vc);return
                                                }
@@ -334,11 +373,9 @@
                                                }
                                }
                                let offSetY = scrollView.contentOffset.y + CGRectGetHeight(scrollView.frame) / 2;
                                if let currentIndex = tableView?.indexPathForRow(at: CGPoint(x: 0, y: offSetY)){
                                                print(scrollView.isDragging)
                                                if !isAnimationing{
                                                if currentShowIndex != currentIndex{
XQMuse/Root/Course/VC/CourseDetialVideoVC.swift
@@ -36,6 +36,7 @@
                                title = "课程详情"
                                videoView = VideoView(url: items[selectIndex.row].videoUrl)
        videoView?.player.play()
                                view_bg_video.addSubview(videoView!)
                                videoView!.snp.makeConstraints { make in
                                                make.edges.equalToSuperview()
XQMuse/Root/Course/VC/CourseVCOfficalCommentVC.swift
@@ -12,8 +12,9 @@
class CourseVCOfficalViewModel:RefreshInnerModel<CourseModel>{
                var cateId = BehaviorRelay<Int?>(value: nil)
    var search = BehaviorRelay<String?>(value: nil)
                override func api() -> (Observable<BaseResponse<BaseResponseList<CourseModel>>>)? {
                                return Services.getCoursePageList(page: page)
        return Services.getCoursePageList(page: page,courseTitle: search.value)
                }
}
@@ -40,7 +41,7 @@
                                Services.getCourseBannerList().subscribe(onNext: {data in
                                                for (index,v) in (data.data ?? []).enumerated(){
                                                                self.bannerModels.append(CommonBannerModel(index: index, id: v.id, name: v.name, resource:v.imageUrl, mediaType: .imageUrl))
                self.bannerModels.append(CommonBannerModel(index: index, id: v.id, name: v.name, resource:v.imageUrl, mediaType: .imageUrl,courseId: v.courseId))
                                                }
                                                self.collectionView.reloadData()
                                }).disposed(by: disposeBag)
XQMuse/Root/Home/CCell/HomeRelaxBanner_2_1_CCell.swift
@@ -15,6 +15,7 @@
                @IBOutlet weak var label_title: UILabel!
                @IBOutlet weak var label_subTitle: UILabel!
                @IBOutlet weak var label_num: UILabel!
    @IBOutlet weak var img_isFree: UIImageView!
                override func awakeFromNib() {
                                super.awakeFromNib()
XQMuse/Root/Home/CCell/HomeRelaxBanner_2_1_CCell.xib
@@ -1,9 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="32700.99.1234" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="23094" 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="22685"/>
        <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="23084"/>
        <capability name="Safe area layout guides" minToolsVersion="9.0"/>
        <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
    </dependencies>
@@ -90,6 +90,7 @@
            <size key="customSize" width="160" height="196"/>
            <connections>
                <outlet property="img_cover" destination="VwD-36-ent" id="93Z-v8-bjM"/>
                <outlet property="img_isFree" destination="C5o-Fs-4Xu" id="eut-gN-uQO"/>
                <outlet property="label_num" destination="Wxc-EY-qwU" id="zxI-Y4-tTv"/>
                <outlet property="label_subTitle" destination="EeQ-hi-VEz" id="U39-7s-GGD"/>
                <outlet property="label_title" destination="6md-5M-Pce" id="j50-e3-otB"/>
XQMuse/Root/Home/CCell/HomeRelaxBanner_2_CCell.swift
@@ -18,6 +18,9 @@
                @IBOutlet weak var label_subTitle: UILabel!
                @IBOutlet weak var label_num: UILabel!
                @IBOutlet weak var cons_maxSubTitle: NSLayoutConstraint!
    @IBOutlet weak var view_price: UIView!
    @IBOutlet weak var label_price: UILabel!
    @IBOutlet weak var image_free: UIImageView!
                
                private var meditationModel:MeditationModel?
                override func awakeFromNib() {
@@ -35,6 +38,8 @@
                                visualEffectView.alpha = 0.7
                                view_text_bg.sendSubviewToBack(visualEffectView)
                                visualEffectView.layer.masksToBounds = true
        view_price.jq_cornerRadius = 12.55
    }
                func setMeditationModel(_ model:MeditationModel){
@@ -50,5 +55,21 @@
                                label_title.text = model.courseTitle
                                label_subTitle.text = model.briefIntroduction
                                label_num.text = "\(model.count)"
        img_vip.isHidden = model.isVip != .yes
        switch model.chargeType {
            case .payment:
                image_free.isHidden = true
                view_price.isHidden = false
                label_price.attributedText = AttributedStringbuilder.build().add(string: "¥", withFont: UIFont(name: "DIN-Bold", size: 7.11) ?? UIFont.systemFont(ofSize: 7, weight: .bold), withColor: .white).add(string: model.generalPrice.jq_formatFloat, withFont: UIFont(name: "DIN-Bold", size: 11.44) ?? .systemFont(ofSize: 11,weight: .bold), withColor: .white).mutableAttributedString
            case .free:
                image_free.isHidden = false
                view_price.isHidden = true
                img_vip.isHidden = true
            case .vipFree:
                image_free.isHidden = true
                view_price.isHidden = true
                img_vip.isHidden = false
        }
                }
}
XQMuse/Root/Home/CCell/HomeRelaxBanner_2_CCell.xib
@@ -1,9 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="32700.99.1234" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="23094" 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="22685"/>
        <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="23084"/>
        <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
    </dependencies>
    <objects>
@@ -64,34 +64,65 @@
                    <imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="icon_vip" translatesAutoresizingMaskIntoConstraints="NO" id="yBF-fO-fwz">
                        <rect key="frame" x="14.666666666666666" y="7.6666666666666661" width="21.333333333333336" height="21.333333333333336"/>
                    </imageView>
                    <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="rmi-DQ-cp9">
                        <rect key="frame" x="14.666666666666664" y="7.6666666666666679" width="25" height="25.000000000000004"/>
                        <subviews>
                            <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Label" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="kTL-dA-lNA">
                                <rect key="frame" x="0.0" y="0.0" width="25" height="25"/>
                                <fontDescription key="fontDescription" type="system" pointSize="11"/>
                                <color key="textColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
                                <nil key="highlightedColor"/>
                            </label>
                        </subviews>
                        <color key="backgroundColor" red="0.89803921568627454" green="0.71372549019607845" blue="0.39215686274509803" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
                        <constraints>
                            <constraint firstAttribute="trailing" secondItem="kTL-dA-lNA" secondAttribute="trailing" id="4rs-Ms-47V"/>
                            <constraint firstAttribute="bottom" secondItem="kTL-dA-lNA" secondAttribute="bottom" id="Gk6-tP-QxW"/>
                            <constraint firstItem="kTL-dA-lNA" firstAttribute="leading" secondItem="rmi-DQ-cp9" secondAttribute="leading" id="Utr-e1-5lW"/>
                            <constraint firstAttribute="width" constant="25.100000000000001" id="j5h-a9-Qj3"/>
                            <constraint firstItem="kTL-dA-lNA" firstAttribute="top" secondItem="rmi-DQ-cp9" secondAttribute="top" id="qKa-MB-Ohi"/>
                            <constraint firstAttribute="height" constant="25.100000000000001" id="xtT-s6-JWf"/>
                        </constraints>
                    </view>
                    <imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="icon_freee" translatesAutoresizingMaskIntoConstraints="NO" id="deT-IZ-PtZ">
                        <rect key="frame" x="8" y="7" width="50" height="18"/>
                    </imageView>
                </subviews>
            </view>
            <constraints>
                <constraint firstItem="yBF-fO-fwz" firstAttribute="top" secondItem="gTV-IL-0wX" secondAttribute="top" constant="7.5" id="136-6N-kY2"/>
                <constraint firstItem="rmi-DQ-cp9" firstAttribute="leading" secondItem="gTV-IL-0wX" secondAttribute="leading" constant="14.5" id="7EM-yV-ddi"/>
                <constraint firstAttribute="bottom" secondItem="cCC-0f-GSV" secondAttribute="bottom" id="FP4-wO-vdE"/>
                <constraint firstItem="deT-IZ-PtZ" firstAttribute="leading" secondItem="gTV-IL-0wX" secondAttribute="leading" constant="8" id="Gs7-Se-Ivy"/>
                <constraint firstAttribute="trailing" secondItem="Fb9-IV-vVk" secondAttribute="trailing" id="HZP-qu-QnA"/>
                <constraint firstItem="yBF-fO-fwz" firstAttribute="leading" secondItem="gTV-IL-0wX" secondAttribute="leading" constant="14.5" id="R10-E8-6fB"/>
                <constraint firstItem="Fb9-IV-vVk" firstAttribute="leading" secondItem="gTV-IL-0wX" secondAttribute="leading" id="WI6-dS-4aK"/>
                <constraint firstAttribute="trailing" secondItem="cCC-0f-GSV" secondAttribute="trailing" id="brF-kM-RJ7"/>
                <constraint firstItem="cCC-0f-GSV" firstAttribute="leading" secondItem="gTV-IL-0wX" secondAttribute="leading" id="c6s-ah-BAB"/>
                <constraint firstAttribute="bottom" secondItem="Fb9-IV-vVk" secondAttribute="bottom" id="jcg-ng-xeW"/>
                <constraint firstItem="deT-IZ-PtZ" firstAttribute="top" secondItem="gTV-IL-0wX" secondAttribute="top" constant="7" id="tPU-LR-azA"/>
                <constraint firstItem="cCC-0f-GSV" firstAttribute="top" secondItem="gTV-IL-0wX" secondAttribute="top" id="tmD-tf-gYR"/>
                <constraint firstItem="rmi-DQ-cp9" firstAttribute="top" secondItem="gTV-IL-0wX" secondAttribute="top" constant="7.5" id="wLQ-lC-KXg"/>
            </constraints>
            <size key="customSize" width="178" height="301"/>
            <connections>
                <outlet property="cons_maxSubTitle" destination="Fam-ne-FM1" id="L5X-GP-uev"/>
                <outlet property="image_free" destination="deT-IZ-PtZ" id="kI7-7g-aIM"/>
                <outlet property="img_cover" destination="cCC-0f-GSV" id="85x-ue-edy"/>
                <outlet property="img_tipPeople" destination="hE1-AV-t8f" id="ObN-5h-jnl"/>
                <outlet property="img_vip" destination="yBF-fO-fwz" id="icq-m9-dx3"/>
                <outlet property="label_num" destination="JaY-19-IAL" id="2RU-X7-0wb"/>
                <outlet property="label_price" destination="kTL-dA-lNA" id="lNC-ej-0H3"/>
                <outlet property="label_subTitle" destination="z5u-My-91l" id="j4L-bl-DhS"/>
                <outlet property="label_title" destination="byc-Ar-sJL" id="CAQ-8Z-yC9"/>
                <outlet property="view_price" destination="rmi-DQ-cp9" id="Kh2-av-YYy"/>
                <outlet property="view_text_bg" destination="Fb9-IV-vVk" id="Ol7-cR-BWU"/>
            </connections>
            <point key="canvasLocation" x="236.64122137404578" y="108.80281690140846"/>
        </collectionViewCell>
    </objects>
    <resources>
        <image name="icon_freee" width="50" height="18"/>
        <image name="icon_use_small" width="10" height="10.666666984558105"/>
        <image name="icon_vip" width="21.666666030883789" height="21.666666030883789"/>
    </resources>
XQMuse/Root/Home/CCell/Home_Style_4_Inner_1_CCell.swift
@@ -19,7 +19,7 @@
                override func awakeFromNib() {
                                super.awakeFromNib()
                                view_shadow.jq_gradientColor(colorArr: [UIColor.black.withAlphaComponent(0.2).cgColor,UIColor.clear.cgColor], cornerRadius: 0, startPoint: CGPoint(x: 1, y: 1), endPoint: CGPoint(x: 1, y: 0), bounds: nil, locations: nil)
        view_shadow.jq_gradientColor(colorArr: [UIColor.black.withAlphaComponent(0.3).cgColor,UIColor.clear.cgColor], cornerRadius: 0, startPoint: CGPoint(x: 1, y: 1), endPoint: CGPoint(x: 1, y: 0), bounds: nil, locations: nil)
                }
XQMuse/Root/Home/CCell/Home_Style_4_Inner_1_CCell.xib
@@ -1,10 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="32700.99.1234" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="23094" 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="22685"/>
        <capability name="System colors in document resources" minToolsVersion="11.0"/>
        <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="23084"/>
        <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
    </dependencies>
    <objects>
@@ -24,7 +23,7 @@
                            <constraint firstAttribute="height" constant="9.5" id="wsl-qN-1LP"/>
                        </constraints>
                    </view>
                    <imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="ajx-e3-nPT">
                    <imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="ajx-e3-nPT">
                        <rect key="frame" x="0.0" y="0.0" width="413" height="255.66666666666666"/>
                    </imageView>
                    <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="all-AA-1bU">
@@ -50,7 +49,6 @@
                                <nil key="highlightedColor"/>
                            </label>
                        </subviews>
                        <color key="backgroundColor" systemColor="systemBackgroundColor"/>
                        <constraints>
                            <constraint firstAttribute="trailing" secondItem="NTV-9E-3YX" secondAttribute="trailing" constant="10" id="1d8-hO-XQO"/>
                            <constraint firstItem="NTV-9E-3YX" firstAttribute="leading" secondItem="tDO-qY-aGP" secondAttribute="leading" id="51K-EF-Rvn"/>
@@ -89,8 +87,5 @@
    </objects>
    <resources>
        <image name="icon_pay_s" width="14.666666984558105" height="18.666666030883789"/>
        <systemColor name="systemBackgroundColor">
            <color white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
        </systemColor>
    </resources>
</document>
XQMuse/Root/Home/HomeVC.swift
@@ -9,6 +9,7 @@
import JQTools
import RxSwift
import MediaPlayer
import MJRefresh
let SetBGMSuccess_Noti = Notification.Name.init("SetBGMSuccess_Noti")
@@ -48,6 +49,10 @@
                                                                AudioPlayer.getSharedInstance().playSceneAt(audioFile)
                                                }
                                }
        tableView.mj_header = MJRefreshNormalHeader(refreshingBlock: {
            self.getData()
        })
                                getData()
    }
@@ -140,6 +145,7 @@
                }
                private func getData(){
        tableView.mj_header?.endRefreshing()
                                Services.getCategoryListByType(type: 1).subscribe(onNext: { data in
                                                var items = [HomeTopMenuItem]()
@@ -183,6 +189,7 @@
                                                                self.viewModel.meditationList.removeAll()
                                                                self.viewModel.meditationList = m
                                                                for v in self.viewModel.meditationList{
                    if v.clientMeditationCategoryVO?.categoryName.isEmpty ?? true{continue}
                                                                                self.titleItems.append(TitleItem(title: v.clientMeditationCategoryVO?.categoryName ?? "", subTitle: v.clientMeditationCategoryVO?.description ?? "",hasMore:true))
                                                                }
                                                                self.tableView.reloadData()
@@ -191,17 +198,13 @@
                }
                @objc func searchAction(){
                                let vc = SearchVC()
        let vc = SearchVC(serchType: .muse)
                                push(vc: vc)
                }
                @objc func settingvoiceAction(){
//                                let vc = BackgroundVoiceVC()
//                                push(vc: vc)
                                 let nav = LoginNav(rootViewController: LoginVC())
                                nav.modalPresentationStyle = .fullScreen
                                present(nav, animated: true)
                                let vc = BackgroundVoiceVC()
                                push(vc: vc)
                }
                @objc func jumpMoreAction(_ sender:UIButton){
@@ -235,16 +238,20 @@
                func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
                                if indexPath.section == 0{
            //每日疗愈
                                                let cell = tableView.dequeueReusableCell(withIdentifier: "_Home_Style_1_TCell") as! Home_Style_1_TCell
                                                cell.model = viewModel.todyModel
                                                return cell
                                }else if indexPath.section == 1{
            //私人定制
                                                let cell = tableView.dequeueReusableCell(withIdentifier: "_Home_Style_4_TCell") as! Home_Style_4_TCell
                                                cell.style = .style1
                                                cell.setModels(viewModel.privateTodyModels)
                                                return cell
                                }else if indexPath.section == 2{
            // 新手冥想指南
                                                let cell = tableView.dequeueReusableCell(withIdentifier: "_Home_Style_2_TCell") as! Home_Style_2_TCell
            cell.imgView.image = UIImage(named: "bg_guide_home")
                                                cell.view_shadow.isHidden = true
                                                return cell
                                }else {
@@ -326,7 +333,9 @@
extension HomeVC:UIScrollViewDelegate{
                func scrollViewDidScroll(_ scrollView: UIScrollView) {
                                let v = min(scrollView.contentOffset.y / JQ_NavBarHeight, 1)
                                navigationController?.navigationBar.standardAppearance.backgroundColor = .white.withAlphaComponent(v)
//                                let v = min(scrollView.contentOffset.y / JQ_NavBarHeight, 1)
//                                navigationController?.navigationBar.standardAppearance.backgroundColor = .white.withAlphaComponent(v)
        navigationController?.navigationBar.standardAppearance.backgroundColor = .white
        navigationController?.navigationBar.scrollEdgeAppearance?.backgroundColor = .white
                }
}
XQMuse/Root/Home/TCell/Home_Style_2_TCell.swift
@@ -11,6 +11,7 @@
class Home_Style_2_TCell: UITableViewCell {
                @IBOutlet weak var view_shadow: UIView!
    @IBOutlet weak var imgView: UIImageView!
                override func awakeFromNib() {
        super.awakeFromNib()
XQMuse/Root/Home/TCell/Home_Style_2_TCell.xib
@@ -1,9 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="32700.99.1234" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="23094" 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="22685"/>
        <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="23084"/>
        <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"/>
@@ -18,7 +18,7 @@
                <rect key="frame" x="0.0" y="0.0" width="475" height="351"/>
                <autoresizingMask key="autoresizingMask"/>
                <subviews>
                    <imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="Pyg-Ek-VBf">
                    <imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="Pyg-Ek-VBf">
                        <rect key="frame" x="0.0" y="0.0" width="475" height="341.66666666666669"/>
                    </imageView>
                    <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="WXB-JU-fQz">
@@ -78,6 +78,7 @@
            </tableViewCellContentView>
            <viewLayoutGuide key="safeArea" id="njF-e1-oar"/>
            <connections>
                <outlet property="imgView" destination="Pyg-Ek-VBf" id="aL8-Jj-6BS"/>
                <outlet property="view_shadow" destination="WXB-JU-fQz" id="PbM-TY-SlG"/>
            </connections>
            <point key="canvasLocation" x="257.25190839694653" y="128.52112676056339"/>
XQMuse/Root/Home/VC/CommentListVC.swift
@@ -29,6 +29,16 @@
                @IBOutlet weak var cons_height: NSLayoutConstraint!
                private var viewModel = CommentListViewModel()
    private var id:Int!
    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()
@@ -63,7 +73,16 @@
                }
                
                @IBAction func sendAction(_ sender: UIButton) {
        guard !tf_input.text!.isEmpty else {
            alert(msg: "请输入您的提问");return
        }
        tf_input.resignFirstResponder()
        Services.addQuestion(content: tf_input.text!, meditationId: id).subscribe(onNext: {_ in
        }, onError: {_ in
        }).disposed(by: disposeBag)
                }
                @objc func longPressAction(_ gesture:UITapGestureRecognizer){
XQMuse/Root/Home/VC/HomeItemDetailVC.swift
@@ -11,6 +11,7 @@
class HomeItemDetailVC: BaseVC,PayMusicDelegate{
                @IBOutlet weak var slider_voice: UISlider!
    @IBOutlet weak var img_background: UIImageView!
                @IBOutlet weak var view_function: UIView!
                @IBOutlet weak var btn_play: UIButton!
                @IBOutlet weak var label_title: UILabel!
@@ -62,17 +63,13 @@
                                Services.getMeditationDetail(id: id).subscribe(onNext: {[unowned self] data in
                                                self.model = data.data
                                                self.collect_bitem.image = data.data?.favorite == .yes ? UIImage(named: "btn_collect_s"):UIImage(named: "btn_collect_1")
                                                self.collect_bitem.image = data.data?.favorite == .yes ? UIImage(named: "btn_collect_1_s"):UIImage(named: "btn_collect_1")
                                                self.collect_bitem.tintColor = data.data?.favorite == .yes ? UIColor(hexString: "fe5b60"):.white
            self.img_background.sd_setImage(with: URL(string: data.data?.backgroundUrl ?? ""))
                                                if audioPlayer.meditationModel?.id == data.data?.id{
                                                                audioPlayer.delegate = self
                                                }
                                }).disposed(by: disposeBag)
                }
                override func viewDidAppear(_ animated: Bool) {
                                super.viewDidAppear(animated)
                                //如果从支付过来的,移除支付
                                navigationController!.viewControllers.removeAll { vc in
@@ -81,6 +78,12 @@
                                                }
                                                return false
                                }
                }
    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)
        (navigationItem.leftBarButtonItem?.customView as? UIButton)?.setImage(UIImage(named: "btn_back")?.withTintColor(.white), for: .normal)
        navigationController?.navigationBar.scrollEdgeAppearance?.backgroundColor = .clear
                }
                override func setUI() {
@@ -124,11 +127,6 @@
                                }.disposed(by: disposeBag)
                }
                override func viewWillAppear(_ animated: Bool) {
                                super.viewWillAppear(animated)
                                (navigationItem.leftBarButtonItem?.customView as? UIButton)?.setImage(UIImage(named: "btn_back")?.withTintColor(.white), for: .normal)
                }
                private func startMiniRunloop(){
                                // 创建旋转动画
                                let rotationAnimation = CABasicAnimation(keyPath: "transform.rotation.z")
@@ -146,13 +144,7 @@
                }
                @IBAction func playAction(_ sender: UIButton) {
//                                showHUD("准备播放")
                                if var m = model{
                                                m.backgroundUrl = "https://downsc.chinaz.net/Files/DownLoad/sound1/201906/11582.mp3,https://www.cambridgeenglish.org/images/153149-movers-sample-listening-test-vol2.mp3"
                                                m.tutorAudioUrl = "https://downsc.chinaz.net/files/download/sound1/201206/1638.mp3"
                                if let m = model{
                                                audioPlayer.playBGMAt(firstPlayIndex: 0, model: m, delegate: self)
                                }
                }
@@ -187,7 +179,9 @@
                }
                @IBAction func commentAction(_ sender: TapBtn) {
                                let vc = CommentListVC()
        guard let m = model else{return}
        let vc = CommentListVC(id: m.id)
                                vc.modalPresentationStyle = .custom
                                present(vc, animated: true)
                }
XQMuse/Root/Home/VC/HomeItemDetailVC.xib
@@ -1,9 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="32700.99.1234" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="23094" 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="22685"/>
        <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="23084"/>
        <capability name="System colors in document resources" minToolsVersion="11.0"/>
        <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
    </dependencies>
@@ -12,6 +12,7 @@
            <connections>
                <outlet property="btn_play" destination="Qgc-UW-rO1" id="MUw-JK-1pS"/>
                <outlet property="btn_playMode" destination="9t3-fS-clT" id="0me-mK-vhP"/>
                <outlet property="img_background" destination="pbM-Fi-Xil" id="cuG-Hk-KlP"/>
                <outlet property="img_countdonw" destination="gxd-0O-eUD" id="rzB-8i-qOk"/>
                <outlet property="label_commentNum" destination="IkS-qR-riK" id="9zO-Xt-6XC"/>
                <outlet property="label_countdown" destination="akf-L4-aPE" id="goO-Gd-TLu"/>
@@ -174,10 +175,10 @@
                    </connections>
                </button>
                <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="3rZ-t0-pdK">
                    <rect key="frame" x="68.666666666666686" y="524.66666666666663" width="256" height="29"/>
                    <rect key="frame" x="71.333333333333329" y="524.66666666666663" width="250.66666666666669" height="29"/>
                    <subviews>
                        <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="当前播放模式已设置为顺序播放" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="4zW-Bq-V7P">
                            <rect key="frame" x="28" y="7.3333333333333712" width="200" height="14"/>
                            <rect key="frame" x="28" y="7.3333333333333712" width="194.66666666666666" height="14"/>
                            <fontDescription key="fontDescription" type="system" pointSize="14"/>
                            <color key="textColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
                            <nil key="highlightedColor"/>
XQMuse/Root/Home/VC/PaymentOrderResultVC.swift
@@ -29,6 +29,14 @@
                                super.viewDidLoad()
                                title = "支付结果"
        //如果从支付过来的,移除支付
        navigationController!.viewControllers.removeAll { vc in
            if vc is PaymentOrderResultVC || vc is PaymentOrderVC{
                return true
            }
            return false
        }
                                NotificationCenter.default.post(name: CourseRefresh_Noti, object: nil)
                                yy_popBlock = { [weak self] () in
@@ -45,7 +53,7 @@
                                                }
                                }
                                topView.setPrice(price)
        topView.setPrice(courseId: courseId, price: price)
                                Services.paymentSuccess(courseId: courseId).subscribe(onNext: {data in
                                                self.models = data.data ?? []
@@ -122,7 +130,8 @@
                func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
                                let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "_HomeRelaxBanner_2_1_CCell", for: indexPath) as! HomeRelaxBanner_2_1_CCell
                                cell.backgroundColor = .jq_randomColor
        let model = models[indexPath.row]
        cell.setCourseModel(model)
                                return cell
                }
XQMuse/Root/Home/VC/PaymentOrderVC.swift
@@ -134,6 +134,20 @@
                @IBAction func completeAction(_ sender: UIButton) {
                                guard let m = courseModel else {return}
        guard btn_isRead.isSelected else {
            alertError(msg: "请先阅读并同意《课程/疗愈音频购买协议》");return
        }
        if giftToOther {
            guard !tf_phone.text!.isEmpty else {
                alertError(msg: "请输入您要赠送人的手机号");return
            }
            guard giftUserId != nil else {
                alertError(msg: "请先查询赠送人是否存在");return
            }
        }
                                guard balance > m.generalPrice else{
                                                CommonAlertView.show(title: "提示", content: "当前余额不足,请先充值", cancelStr: "暂不充值", completeStr: "去充值", isSingle: false) { state in
@@ -142,16 +156,6 @@
                                                                }
                                                }
                                                return
                                }
                                guard btn_isRead.isSelected else {
                                                alertError(msg: "请先阅读并同意《课程/疗愈音频购买协议》");return
                                }
                                if giftToOther {
                                                guard giftUserId != nil else {
                                                                alertError(msg: "请输入您要赠送人的手机号");return
                                                }
                                }
                                let vc = PaymentOrderResultVC(courseId: courseId, price: m.generalPrice)
XQMuse/Root/Home/VC/SearchContentVC.swift
@@ -24,11 +24,23 @@
                @IBOutlet weak var tf_search: UITextField!
                @IBOutlet weak var collectionView: UICollectionView!
                private var viewModel = SearchContentViewModel()
    private var museViewModel:SearchContentViewModel?
    private var courseViewModel:CourseVCOfficalViewModel?
    private var serchType:SearchVC.SearchType!
                init(content:String) {
    init(content:String,type:SearchVC.SearchType) {
                                super.init(nibName: nil, bundle: nil)
                                self.viewModel.search.accept(content)
        self.serchType = type
        if type == .course{
            courseViewModel = CourseVCOfficalViewModel()
            courseViewModel?.search.accept(content)
        }
        if type == .muse{
            museViewModel = SearchContentViewModel()
            museViewModel?.search.accept(content)
        }
                }
                
                required init?(coder: NSCoder) {
@@ -39,7 +51,11 @@
        super.viewDidLoad()
                                title = "心泉·疗愈"
                                tf_search.text = viewModel.search.value
        switch serchType{
            case .course:tf_search.text = courseViewModel?.search.value ?? ""
            case .muse:tf_search.text = museViewModel?.search.value ?? ""
            default:break
        }
    }
                override func setUI() {
@@ -54,7 +70,12 @@
                                collectionView.register(UINib(nibName: "HomeRelaxBanner_2_CCell", bundle: nil), forCellWithReuseIdentifier: "_HomeRelaxBanner_2_CCell")
                                collectionView.emptyDataSetView {[unowned self] v in
            guard v.viewWithTag(1301) == nil else {return}
                                                let emptyImageView = UIImageView(image: UIImage(named: "bg_empty"))
            emptyImageView.tag = 1301
                                                v.addSubview(emptyImageView)
                                                emptyImageView.snp.makeConstraints { make in
                                                                make.top.equalTo(56.5)
@@ -71,8 +92,15 @@
                                                }
                                }
                                viewModel.configure(collectionView)
                                viewModel.beginRefresh()
        switch serchType{
            case .course:
                self.courseViewModel?.configure(collectionView)
                self.courseViewModel?.beginRefresh()
            case .muse:
                self.museViewModel?.configure(collectionView)
                self.museViewModel?.beginRefresh()
            default:break
        }
                }
@@ -83,8 +111,15 @@
                                                alert(msg: "请输入搜索内容");return
                                }
                                viewModel.search.accept(tf_search.text!)
                                viewModel.beginRefresh()
        switch serchType{
            case .course:
                self.courseViewModel?.search.accept(tf_search.text!)
                self.courseViewModel?.beginRefresh()
            case .muse:
                self.museViewModel?.search.accept(tf_search.text!)
                self.museViewModel?.beginRefresh()
            default:break
        }
                }
}
@@ -92,21 +127,46 @@
extension SearchContentVC:UICollectionViewDelegate & UICollectionViewDataSource{
                func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
                                let m = viewModel.dataSource.value!.list[indexPath.row]
        switch serchType{
            case .course:
                let m = courseViewModel!.dataSource.value!.list[indexPath.row]
                                let vc = CourseDetialVC(courseId: m.id)
                                JQ_currentViewController().jq_push(vc: vc)
            case .muse:
                let m = museViewModel!.dataSource.value!.list[indexPath.row]
                let vc = HomeItemDetailVC(id: m.id)
                JQ_currentViewController().jq_push(vc: vc)
            default:break
        }
                }
                func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
                                let m = viewModel.dataSource.value!.list[indexPath.row]
                                let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "_HomeRelaxBanner_2_CCell", for: indexPath) as! HomeRelaxBanner_2_CCell
                                cell.backgroundColor = .jq_randomColor
        switch serchType{
            case .course:break
            case .muse:
                let m = museViewModel!.dataSource.value!.list[indexPath.row]
                                cell.setMeditationModel(m)
            default:break
        }
                                return cell
                }
                func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
                                return viewModel.dataSource.value?.list.count ?? 0
        switch serchType{
            case .course:
                return courseViewModel!.dataSource.value?.list.count ?? 0
            case .muse:
                return museViewModel!.dataSource.value?.list.count ?? 0
            default:return 0
        }
                }
}
@@ -136,9 +196,15 @@
                                                alert(msg: "请输入搜索内容")
                                                return true
                                }
                                viewModel.search.accept(textField.text!)
                                viewModel.beginRefresh()
        switch serchType{
            case .course:
                self.courseViewModel?.search.accept(tf_search.text!)
                self.courseViewModel?.beginRefresh()
            case .muse:
                self.museViewModel?.search.accept(tf_search.text!)
                self.museViewModel?.beginRefresh()
            default:break
        }
                                return true
                }
}
XQMuse/Root/Home/VC/SearchVC.swift
@@ -15,12 +15,12 @@
                static var array = NSMutableArray()
                static let cacheSearchPath = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first!.appendingPathComponent("search")
                static func readList()->NSMutableArray{
    static func readList(_ serchType:SearchVC.SearchType)->NSMutableArray{
                                if !FileManager.default.fileExists(atPath: cacheSearchPath.absoluteString){
                                                try? FileManager.default.createDirectory(at: cacheSearchPath, withIntermediateDirectories: true)
                                }
                                let searchPlistPath = cacheSearchPath.appendingPathComponent("search.plist")
        let searchPlistPath = cacheSearchPath.appendingPathComponent(serchType.infoPlist)
                                if let tempArray = NSMutableArray(contentsOfFile: searchPlistPath.droppedScheme()!.absoluteString){
                                                array = tempArray
                                }
@@ -43,8 +43,8 @@
                                }
                }
                static func writeToPath(){
                                let searchPlistPath = cacheSearchPath.appendingPathComponent("search.plist")
    static func writeToPath(_ serchType:SearchVC.SearchType){
        let searchPlistPath = cacheSearchPath.appendingPathComponent(serchType.infoPlist)
                                array.write(to: searchPlistPath, atomically: true)
                }
@@ -54,18 +54,48 @@
}
class SearchVC: BaseVC {
    enum SearchType {
        case muse //疗愈
        case course //课程
        var infoPlist:String{
            switch self {
                case .muse:return "searchmuse.plist"
                case .course:return "searchcourse.plist"
            }
        }
    }
                @IBOutlet weak var cacheSearchCollectionView: UICollectionView!
                @IBOutlet weak var cacheSearchHei: NSLayoutConstraint!
                @IBOutlet weak var tf_search: UITextField!
                @IBOutlet weak var tableView: UITableView!
    @IBOutlet weak var view_hotKeyword: UIView!
    @IBOutlet weak var label_hotSearhTitle: UILabel!
                private var hotWords = [String]()
    private var serchType:SearchType!
    init(serchType:SearchType) {
        super.init(nibName: nil, bundle: nil)
        self.serchType = serchType
    }
    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
                override func viewDidLoad() {
                                super.viewDidLoad()
                                title = "心泉·疗愈"
                                _ = SearchCache.readList()
        view_hotKeyword.isHidden = serchType == .course
        label_hotSearhTitle.isHidden = serchType == .course
        tf_search.placeholder = serchType == .course ? "搜索你喜欢的课程~":"请输入冥想搜索内容"
        _ = SearchCache.readList(serchType)
                                cacheSearchCollectionView.reloadData()
                                Services.getHotWordList().subscribe(onNext: {data in
@@ -78,7 +108,7 @@
                override func viewDidDisappear(_ animated: Bool) {
                                super.viewDidDisappear(animated)
                                SearchCache.writeToPath()
        SearchCache.writeToPath(serchType)
                }
                override func setUI() {
@@ -139,7 +169,7 @@
                                tf_search.resignFirstResponder()
                                SearchCache.writeToList(tf_search.text!)
                                let vc = SearchContentVC(content: tf_search.text!)
        let vc = SearchContentVC(content: tf_search.text!, type: serchType)
                                jq_push(vc: vc)
                }
}
XQMuse/Root/Home/VC/SearchVC.xib
@@ -1,9 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="32700.99.1234" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="23094" 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="22685"/>
        <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="23084"/>
        <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"/>
@@ -13,9 +13,11 @@
            <connections>
                <outlet property="cacheSearchCollectionView" destination="hyl-1O-IfF" id="xLr-Xr-lJL"/>
                <outlet property="cacheSearchHei" destination="5YE-JH-tVc" id="ktS-NR-z7Y"/>
                <outlet property="label_hotSearhTitle" destination="Mda-xm-ljU" id="sc7-eb-G0P"/>
                <outlet property="tableView" destination="RTG-Tg-r7D" id="pq2-Aa-jvq"/>
                <outlet property="tf_search" destination="Rbv-zT-iOu" id="Dxb-Mb-ezs"/>
                <outlet property="view" destination="i5M-Pr-FkT" id="sfx-zR-JGt"/>
                <outlet property="view_hotKeyword" destination="U44-7x-wSJ" id="I6D-Jd-rhG"/>
            </connections>
        </placeholder>
        <placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
@@ -64,7 +66,7 @@
                    </connections>
                </button>
                <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="历史搜索" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="gQh-cp-6ml">
                    <rect key="frame" x="24" y="156" width="69.333333333333329" height="16"/>
                    <rect key="frame" x="24" y="156" width="67.666666666666671" height="16"/>
                    <constraints>
                        <constraint firstAttribute="height" constant="16" id="qdH-3T-iMm"/>
                    </constraints>
@@ -86,7 +88,7 @@
                    </collectionViewFlowLayout>
                </collectionView>
                <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="热门搜索" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Mda-xm-ljU">
                    <rect key="frame" x="24" y="245.66666666666666" width="69.333333333333329" height="15.999999999999972"/>
                    <rect key="frame" x="24" y="245.66666666666666" width="67.666666666666671" height="15.999999999999972"/>
                    <constraints>
                        <constraint firstAttribute="height" constant="16" id="WZa-u0-Fx3"/>
                    </constraints>
XQMuse/Root/Home/View/PaymentOrderResultTopView.swift
@@ -12,12 +12,14 @@
                @IBOutlet weak var label_price: UILabel!
                @IBOutlet weak var btn_lookCourse: UIButton!
    private var courseId:Int!
                override func awakeFromNib() {
                                super.awakeFromNib()
                }
                func setPrice(_ price:Double){
    func setPrice(courseId:Int,price:Double){
        self.courseId = courseId
                                label_price.text = "\(price.jq_formatFloat)"
                }
@@ -26,8 +28,8 @@
                }
                @IBAction func lookCourseAction(_ sender: UIButton) {
//                            let vc    = HomeItemDetailVC()
//                                JQ_currentViewController().jq_push(vc: vc)
        let vc = CourseDetialVC(courseId: courseId)
        JQ_currentViewController().jq_push(vc: vc)
                }
                
XQMuse/Root/Login/LoginVC.swift
@@ -57,6 +57,7 @@
                @IBOutlet weak var btn_login: UIButton!
                @IBOutlet weak var btn_sendCode: UIButton!
                @IBOutlet weak var btn_isRead: UIButton!
    @IBOutlet weak var btn_wechat: UIButton!
                private var viewModel = LoginViewModel()
@@ -117,6 +118,8 @@
                override func setUI() {
        btn_wechat.isHidden = !WXApi.isWXAppInstalled()
        navigationItem.leftBarButtonItem = UIBarButtonItem.jq_creat(image: nav_back_img, target: self, alignment:.left, action: #selector(backAction)).item
                                btn_eye.isSelected = true
@@ -164,7 +167,7 @@
                                guard !viewModel.loginPhone.value.isEmpty else {alert(msg: "请输入手机号");return}
                                guard viewModel.loginPhone.value.jq_isPhone else {alert(msg: "请输入正确手机号");return}
                                Services.sendCode(type: .codeLogin).subscribe(onNext: {data in
        Services.sendCode(phone:tf_phone.text!,type: .codeLogin).subscribe(onNext: {data in
                                                if let _ = data.data{
                                                                sender.jq_openCountDown(60, defultTitle: "发送验证码") {
                                                                                sender.titleLabel?.font = UIFont.systemFont(ofSize: 12)
@@ -229,7 +232,7 @@
        guard btn_isRead.isSelected else {
            alertError(msg: "请阅读并同意《用户注册协议》和《用户隐私协议》");return
        }
                                //todo
        WeChatTools.sendAuthRequest()
                }
                @IBAction func loginByAppleAction(_ sender: UIButton) {
XQMuse/Root/Login/LoginVC.xib
@@ -1,9 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="32700.99.1234" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="23094" 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="22685"/>
        <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="23084"/>
        <capability name="System colors in document resources" minToolsVersion="11.0"/>
        <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
    </dependencies>
@@ -17,6 +17,7 @@
                <outlet property="btn_loginByPwd" destination="Ec8-sg-6R6" id="Y2P-aU-5lk"/>
                <outlet property="btn_register" destination="k1h-gO-9vj" id="AxQ-S9-3oN"/>
                <outlet property="btn_sendCode" destination="cUd-a4-RTn" id="n26-3e-uaI"/>
                <outlet property="btn_wechat" destination="2Fj-Y0-NYp" id="M7L-LL-Se8"/>
                <outlet property="tf_content" destination="x0Y-XG-Xsv" id="GVf-UU-yCe"/>
                <outlet property="tf_phone" destination="9rD-4T-K6b" id="ynF-y5-xQD"/>
                <outlet property="view" destination="i5M-Pr-FkT" id="sfx-zR-JGt"/>
@@ -35,7 +36,7 @@
                    <rect key="frame" x="0.0" y="248" width="393" height="604"/>
                    <subviews>
                        <button opaque="NO" tag="10" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="Ec8-sg-6R6">
                            <rect key="frame" x="23" y="22" width="74" height="22"/>
                            <rect key="frame" x="23" y="22" width="72" height="22"/>
                            <constraints>
                                <constraint firstAttribute="height" constant="22" id="eDS-Kw-vhp"/>
                            </constraints>
@@ -49,7 +50,7 @@
                            </connections>
                        </button>
                        <button opaque="NO" tag="11" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="Afa-A3-2l1">
                            <rect key="frame" x="125" y="22" width="92" height="22"/>
                            <rect key="frame" x="123" y="22" width="90" height="22"/>
                            <constraints>
                                <constraint firstAttribute="height" constant="22" id="na9-Gz-KYA"/>
                            </constraints>
@@ -66,7 +67,7 @@
                            <rect key="frame" x="31" y="118" width="24" height="24"/>
                        </imageView>
                        <textField opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="248" contentHorizontalAlignment="left" contentVerticalAlignment="center" placeholder="请输入您的手机号" textAlignment="natural" minimumFontSize="17" translatesAutoresizingMaskIntoConstraints="NO" id="9rD-4T-K6b" customClass="QMUITextField">
                            <rect key="frame" x="66" y="120.6666666666667" width="114.33333333333331" height="18.666666666666671"/>
                            <rect key="frame" x="66" y="120.6666666666667" width="111.33333333333331" height="18.666666666666671"/>
                            <fontDescription key="fontDescription" type="system" pointSize="14"/>
                            <textInputTraits key="textInputTraits" keyboardType="numberPad"/>
                            <userDefinedRuntimeAttributes>
@@ -86,7 +87,7 @@
                            <rect key="frame" x="31" y="187" width="24" height="24"/>
                        </imageView>
                        <textField opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="248" contentHorizontalAlignment="left" contentVerticalAlignment="center" placeholder="请输入密码" textAlignment="natural" minimumFontSize="17" translatesAutoresizingMaskIntoConstraints="NO" id="x0Y-XG-Xsv" customClass="QMUITextField">
                            <rect key="frame" x="66" y="189.66666666666669" width="71.666666666666686" height="18.666666666666657"/>
                            <rect key="frame" x="66" y="189.66666666666669" width="69.666666666666686" height="18.666666666666657"/>
                            <fontDescription key="fontDescription" type="system" pointSize="14"/>
                            <textInputTraits key="textInputTraits"/>
                        </textField>
@@ -132,7 +133,7 @@
                            </connections>
                        </button>
                        <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="EBj-o7-Mca">
                            <rect key="frame" x="31" y="357" width="56" height="27"/>
                            <rect key="frame" x="31" y="357" width="54" height="27"/>
                            <fontDescription key="fontDescription" type="system" pointSize="12"/>
                            <inset key="imageEdgeInsets" minX="0.0" minY="0.0" maxX="2.2250738585072014e-308" maxY="0.0"/>
                            <state key="normal" title="忘记密码?">
@@ -143,7 +144,7 @@
                            </connections>
                        </button>
                        <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="k1h-gO-9vj">
                            <rect key="frame" x="312" y="357" width="50" height="27"/>
                            <rect key="frame" x="314" y="357" width="48" 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="注册账号">
@@ -175,13 +176,13 @@
                            </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="9Rg-d1-NE7">
                            <rect key="frame" x="166" y="441.66666666666663" width="61.333333333333343" height="14.333333333333314"/>
                            <rect key="frame" x="166.66666666666666" y="441.66666666666663" width="59.666666666666657" height="14.333333333333314"/>
                            <fontDescription key="fontDescription" type="system" pointSize="12"/>
                            <color key="textColor" red="0.5725490196078431" green="0.56862745098039214" blue="0.56862745098039214" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
                            <nil key="highlightedColor"/>
                        </label>
                        <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="cUd-a4-RTn">
                            <rect key="frame" x="293" y="184.66666666666669" width="72" height="29"/>
                            <rect key="frame" x="295" y="184.66666666666669" width="70" height="29"/>
                            <fontDescription key="fontDescription" type="system" weight="medium" pointSize="14"/>
                            <inset key="imageEdgeInsets" minX="0.0" minY="0.0" maxX="2.2250738585072014e-308" maxY="0.0"/>
                            <state key="normal" title="发送验证码">
@@ -205,13 +206,13 @@
                            </connections>
                        </button>
                        <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="我已阅读并同意" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="esZ-HR-QwQ">
                            <rect key="frame" x="57" y="240" width="86" height="14.333333333333343"/>
                            <rect key="frame" x="57.000000000000007" y="240" width="83.666666666666686" height="14.333333333333343"/>
                            <fontDescription key="fontDescription" type="system" weight="medium" pointSize="12"/>
                            <color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="0.59999999999999998" colorSpace="custom" customColorSpace="sRGB"/>
                            <nil key="highlightedColor"/>
                        </label>
                        <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="MNJ-Ag-zfE">
                            <rect key="frame" x="148" y="233.66666666666669" width="87" height="27"/>
                            <rect key="frame" x="145.66666666666666" y="233.66666666666669" width="84" 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="《用户注册协议》">
@@ -222,7 +223,7 @@
                            </connections>
                        </button>
                        <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="eq2-Wp-Yza">
                            <rect key="frame" x="243" y="233.66666666666669" width="87" height="27"/>
                            <rect key="frame" x="237.66666666666663" y="233.66666666666669" width="84" 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="《用户隐私协议》">
XQMuse/Root/Login/VC/ForgotPasswordInputCodeVC.swift
@@ -94,7 +94,7 @@
                private func sendCode(){
                                Services.sendCode(type: .forgetPwd).subscribe(onNext: { _ in
        Services.sendCode(phone:phone,type: .forgetPwd).subscribe(onNext: { _ in
                                                self.starTimer()
                                }).disposed(by: disposeBag)
                }
XQMuse/Root/Login/VC/RegisterVC.swift
@@ -89,8 +89,8 @@
                                guard !viewModel.phone.value.isEmpty else {alertError(msg: "请输入手机号");return}
                                guard viewModel.phone.value.jq_isPhone else {alertError(msg: "请输入正确手机号");return}
                                Services.sendCode(type: .register).subscribe(onNext: {data in
                                                if let _ = data.data{
        Services.sendCode(phone:viewModel.phone.value,type: .register).subscribe(onNext: {data in
            if data.code == 200{
                                                                sender.jq_openCountDown(60, defultTitle: "发送验证码") {
                                                                                sender.titleLabel?.font = UIFont.systemFont(ofSize: 12)
                                                                                sender.setTitleColor(.black.withAlphaComponent(0.3), for: .normal)
XQMuse/Root/Login/VC/UpdatePhoneVC.swift
@@ -38,7 +38,7 @@
            alertError(msg: "请输入正确的手机号");return
        }
        Services.sendCode(type: .threePlantform).subscribe(onNext: {data in
        Services.sendCode(phone:tf_phone.text!,type: .threePlantform).subscribe(onNext: {data in
            if let _ = data.data{
                sender.jq_openCountDown(60, defultTitle: "发送验证码") {
                    sender.titleLabel?.font = UIFont.systemFont(ofSize: 12)
XQMuse/Root/Me/MeVC.xib
@@ -276,8 +276,12 @@
                                                            <color key="textColor" red="0.13725490196078433" green="0.13725490196078433" blue="0.13725490196078433" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
                                                            <nil key="highlightedColor"/>
                                                        </label>
                                                        <imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="icon_vip_level" translatesAutoresizingMaskIntoConstraints="NO" id="dut-7H-aMv">
                                                            <rect key="frame" x="70.333333333333314" y="11.333333333333373" width="95.666666666666686" height="27.666666666666671"/>
                                                        <imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="icon_vip_level" translatesAutoresizingMaskIntoConstraints="NO" id="dut-7H-aMv">
                                                            <rect key="frame" x="70.333333333333343" y="11.333333333333373" width="95.333333333333343" height="27.666666666666671"/>
                                                            <constraints>
                                                                <constraint firstAttribute="width" constant="95.5" id="9QQ-4F-lHB"/>
                                                                <constraint firstAttribute="height" constant="27.5" id="vly-QN-iWG"/>
                                                            </constraints>
                                                        </imageView>
                                                        <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="查看详情" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="flg-Hv-HHC">
                                                            <rect key="frame" x="266.66666666666669" y="18.666666666666742" width="44" height="13.333333333333336"/>
XQMuse/Root/Me/VC/AddBankInfoVC.swift
@@ -119,7 +119,7 @@
                                                alertError(msg: "请输入手机号");return
                                }
                                Services.sendCode(type: .addBank).subscribe(onNext: {_ in
        Services.sendCode(phone:tf_phone.text!,type: .addBank).subscribe(onNext: {_ in
                                                sender.jq_openCountDown(60, defultTitle: "发送验证码") {
                                                                sender.titleLabel?.font = UIFont.systemFont(ofSize: 12)
                                                                sender.setTitleColor(.black.withAlphaComponent(0.3), for: .normal)
XQMuse/Root/Me/VC/BindPhone_2_VC.swift
@@ -20,7 +20,7 @@
    }
                @IBAction func sendCodeAction(_ sender: UIButton) {
                                Services.sendCode(type: .exchangePhone).subscribe(onNext: { data in
        Services.sendCode(phone:tf_phone.text!,type: .exchangePhone).subscribe(onNext: { data in
                                                if let _ = data.data{
                                                                sender.jq_openCountDown(60, defultTitle: "发送验证码") {
                                                                                sender.titleLabel?.font = UIFont.systemFont(ofSize: 12)
XQMuse/Root/Network/Models.swift
@@ -116,6 +116,7 @@
                var tutorAudioUrl: String = ""
                var virtualLearnedNum: Int = 0
                var favorite:ConditionType = .no // 是否收藏:1:是 2:否
    var meditationMusicList = [String]()
}
struct CommentModel:HandyJSON{
@@ -157,6 +158,7 @@
                var id = 0
                var imageUrl = ""
                var name = ""
    var courseId:String?
}
struct CourseModel:HandyJSON{
@@ -184,6 +186,7 @@
                var sortNum: Int = 0
                var tutor:String = ""
                var wxQrCode:String = ""
    var isCollect:ConditionType = .no // 是否收藏:1:是 2:否
                var list2 = [CourseModel]()
                var list = [CourseItemModel]()
@@ -457,7 +460,7 @@
struct ResponseUserAnswerModel:HandyJSON{
                var tagsId = "" //问题二 多个tagId使用英文逗号拼接字符串
                var tagIds = "" //问题二 多个tagId使用英文逗号拼接字符串
                var userAnswerOneDTOList = [ResponseUserAnswerDTOModel]()
}
XQMuse/Root/Network/NetworkRequest.swift
@@ -193,10 +193,10 @@
                                                if progress {showHUD()}
                                                var headers = HTTPHeaders()
//                                                if let token = UserViewModel.getToken(){
//                                                                headers.add(name: "Authorization", value: "Bearer" + " " + token)
//                                                                LogInfo("USER_token:Bearer \(token)")
//                                                }
            if let token = UserViewModel.getLoginInfo()?.accessToken{
                                                                headers.add(name: "Authorization", value: "Bearer" + " " + token)
                                                                LogInfo("USER_token:Bearer \(token)")
                                                }
                                                if encoding is JSONEncoding {
                                                                headers.add(name: "Content-Type", value: "application/json;charset=UTF-8")
@@ -206,11 +206,11 @@
                                                if encoding != nil {
                                                                newEncoding = encoding!
                                                } else {
                                                                #if DEBUG
                                                                newEncoding = URLEncoding.queryString
                                                                #else
//                                                                #if DEBUG
//                                                                newEncoding = URLEncoding.queryString
//                                                                #else
                                                                newEncoding = method == .post ? URLEncoding.httpBody : URLEncoding.queryString
                                                                #endif
//                                                                #endif
                                                }
                                                sharedSessionManager.request(params.url.absoluteString, method: method, parameters:params.done(), encoding: newEncoding, headers:headers).validate().responseData{response in
@@ -237,16 +237,7 @@
                                                                                if let next = BaseResponse<T>.deserialize(from: jsonString){
                                                                                                switch next.code{
                                                                                                                case 200:ob.onNext(next)
                                                                                                                case 501:
//                                                                                                                                CommonAlertView.show(title: "提示", content: next.msg,isSingle: true) { _ in
//
//                                                                                                                                }
                                                                                                                                ob.onError(NetRequestError.InvaildSession)
                                                                                                                case 600:
                                                                                                                                if !ignoreAlert{
                                                                                                                                                alertError(msg: "登录失效,请重新登录");ob.onError(NetRequestError.InvaildSession)
                                                                                                                                }
//                                                                                                                                app.needLogin()
                            case 401:ob.onError(NetRequestError.InvaildSession)
                                                                                                                default:
                                                                                                                                if !ignoreAlert{
                                                                                                                                                alertError(msg: "\(next.msg)")
XQMuse/Root/Network/Services.swift
@@ -13,7 +13,8 @@
import CoreLocation
#if DEBUG
let All_Url = "https://mock.apipost.net/mock/31b303c60464000"
let All_Url = "http://192.168.110.64:9000"
//let All_Url = "https://mock.apipost.net/mock/31b303c60464000"
#else
let All_Url = "http://" //正式地址
#endif
@@ -41,7 +42,7 @@
                                                                                .append(key: "captcha",value:content)
                                                                                .append(key: "apipost_id", value: "246d780670e265")
                                }
                                return NetworkRequest.request(params: params, method: .post, progress: true)
        return NetworkRequest.request(params: params, method: .post,encoding: JSONEncoding(), progress: true)
                }
@@ -50,6 +51,17 @@
        params.interface(url: "/auth/app/appleLogin")
            .append(key: "appleId", value: appleId)
            .append(key: "apipost_id", value: "246d780670e264")
        return NetworkRequest.request(params: params, method: .post, progress: true)
    }
    class func loginByWechat(headImgUrl:String,nickname:String,sex:Int,wxOpenId:String)->Observable<BaseResponse<LoginUserInfoModel>>{
        let params = ParamsAppender.build(url: All_Url)
        params.interface(url: "/auth/app/appleLogin")
            .append(key: "headImgUrl", value: headImgUrl)
            .append(key: "nickname", value: nickname)
            .append(key: "sex", value: sex)
            .append(key: "wxOpenId", value: wxOpenId)
            .append(key: "apipost_id", value: "246d7806b0e26c")
        return NetworkRequest.request(params: params, method: .post, progress: true)
    }
@@ -68,10 +80,11 @@
    }
                /// 发送验证码
                class func sendCode(type:SendCodeType)->Observable<BaseResponse<SimpleModel>>{
    class func sendCode(phone:String,type:SendCodeType)->Observable<BaseResponse<SimpleModel>>{
                                let params = ParamsAppender.build(url: All_Url)
                                params.interface(url: "/auth/app/sendCaptchaCode")
                                                .append(key: "type", value: type.rawValue)
            .append(key: "cellPhone", value: phone)
                                                .append(key: "apipost_id", value: "246d7806b0e269")
                                return NetworkRequest.request(params: params, method: .get, progress: true)
                }
@@ -85,7 +98,7 @@
                                                .append(key: "inviteUserId", value: inviteUserId)
                                                .append(key: "password", value: password.jq_md5String().uppercased())
                                                .append(key: "apipost_id", value: "246d7806b0e268")
                                return NetworkRequest.request(params: params, method: .post, progress: true)
        return NetworkRequest.request(params: params, method: .post,encoding: JSONEncoding(), progress: true)
                }
                /// 找回密码验证手机号
@@ -201,7 +214,7 @@
                                params.interface(url: "/meditation/client/meditation/home/favorite")
                                                .append(key: "id", value: id)
                                                .append(key: "apipost_id", value: "2aa4e14ab0e159")
                                return NetworkRequest.request(params: params, method: .get, progress: true)
                                return NetworkRequest.request(params: params, method: .post, progress: false)
                }
                /// 获取热词
@@ -215,12 +228,12 @@
                /// 搜索
                class func search(text:String,page:Int,pageSize:Int = 20)->Observable<BaseResponse<BaseResponseList<MeditationModel>>>{
                                let params = ParamsAppender.build(url: All_Url)
                                params.interface(url: "/meditation/client/meditation/home/getHotWordList")
                                params.interface(url: "/meditation/client/meditation/home/search")
                                                .append(key: "condition", value: text)
                                                .append(key: "pageCurr", value: page)
                                                .append(key: "pageSize", value: pageSize)
                                                .append(key: "apipost_id", value: "25c3e3d0b0e160")
                                return NetworkRequest.request(params: params, method: .get, progress: false)
                                return NetworkRequest.request(params: params, method: .post, progress: false)
                }
}
@@ -372,7 +385,7 @@
                                let params = ParamsAppender.build(url: All_Url)
                                params.interface(url: "/user/client/app-user/getTagList")
                                                .append(key: "apipost_id", value: "25c3dab9f0e024")
                                return NetworkRequest.request(params: params, method: .post, progress: true)
                                return NetworkRequest.request(params: params, method: .get, progress: true)
                }
                class func saveUserAnswers(_ model:ResponseUserAnswerModel)->Observable<BaseResponse<SimpleModel>>{
@@ -380,7 +393,7 @@
                                params.interface(url: "/user/client/app-user/saveUserAnswers")
                                                .append(dic: model.toJSON()!)
                                                .append(key: "apipost_id", value: "25c3dab9f0e025")
                                return NetworkRequest.request(params: params, method: .post, progress: true)
        return NetworkRequest.request(params: params, method: .post,encoding: JSONEncoding(), progress: true)
                }
                /// 冥想等级
@@ -607,6 +620,12 @@
                                return NetworkRequest.request(params: params, method: .post, progress: false)
                }
    class func addQuestion(content:String,meditationId:Int)->Observable<BaseResponse<SimpleModel>>{
        let params = ParamsAppender.build(url: All_Url)
            .interface(url: "/meditation/client/meditation/home/addQuestion")
        return NetworkRequest.request(params: params, method: .post, progress: true)
    }
                /// 问题列表
                class func commonQuestionDetailBy(id:Int)->Observable<BaseResponse<CommonQuestionModel>>{
                                let params = ParamsAppender.build(url: All_Url)
XQMuse/Root/Other/View/CommonBannerView.swift
@@ -13,6 +13,7 @@
                var name:String? //名称
                var resource:String? //数据源:URL等
                var mediaType:CommonBannerView.MediaType?
    var courseId:String?
}
class CommonBannerView: UIView, UICollectionViewDelegate, UICollectionViewDataSource,UICollectionViewDelegateFlowLayout {
XQMuse/Root/Pavilion/VC/PavilionDetailVC.xib
@@ -1,9 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="32700.99.1234" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="23094" 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="22685"/>
        <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="23084"/>
        <capability name="System colors in document resources" minToolsVersion="11.0"/>
        <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
    </dependencies>
@@ -40,7 +40,7 @@
                                    </constraints>
                                </view>
                                <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="心泉疗愈馆" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="ej2-gY-nmo">
                                    <rect key="frame" x="26.666666666666671" y="346" width="102.00000000000001" height="24"/>
                                    <rect key="frame" x="26.666666666666671" y="346" width="96" height="24"/>
                                    <fontDescription key="fontDescription" type="system" weight="medium" pointSize="20"/>
                                    <color key="textColor" red="0.039215686274509803" green="0.25882352941176467" blue="0.074509803921568626" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
                                    <nil key="highlightedColor"/>
@@ -144,7 +144,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="Dmh-Sc-k0l">
                                    <rect key="frame" x="26.666666666666671" y="484.33333333333331" width="41" height="24"/>
                                    <rect key="frame" x="26.666666666666668" y="484.33333333333331" width="38.333333333333329" height="24"/>
                                    <fontDescription key="fontDescription" type="system" weight="medium" pointSize="20"/>
                                    <color key="textColor" red="0.039215686270000001" green="0.25882352939999997" blue="0.074509803920000006" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
                                    <nil key="highlightedColor"/>
XQMuse/Root/Pavilion/VC/PavilionSearchVC.swift
@@ -63,8 +63,8 @@
                func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
                                let model = viewModel!.dataSource.value!.list[indexPath.row]
                                let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "_PavilionItemCell", for: indexPath) as! PavilionItemCell
                                cell.backgroundColor = .jq_randomColor
                                cell.jq_cornerRadius = 16
        cell.backgroundColor = .white
                                cell.setPavilionDetailModel(model)
                                return cell
                }
XQMuse/Root/Plans/PlanGuideVC.swift
@@ -11,6 +11,8 @@
let PlantGuideQuit_Noti = Notification.Name.init(rawValue: "PlantGuideQuit_Noti")
let backgroundVoiceUrl = "https://xqgwzh.obs.cn-south-1.myhuaweicloud.com/question/backgroundQuestion.wav"
class PlanGuideVC: BaseVC {
                @IBOutlet weak var view_gradient: UIView!
@@ -19,6 +21,8 @@
                @IBOutlet weak var label_subTitle: UILabel!
                @IBOutlet weak var label_info: UILabel!
                @IBOutlet weak var btn_custom: UIButton!
    private let masterPlayer = AudioPlayer.getSharedInstance()
                private lazy var player:AVPlayer = {
                                let bgPath = Bundle.main.url(forResource: "bg_movie", withExtension: "mov")
@@ -35,7 +39,7 @@
                override func viewDidLoad() {
                                super.viewDidLoad()
        masterPlayer.playBGMAt(firstPlayIndex: 0, model: MeditationModel(backgroundUrl:backgroundVoiceUrl), delegate: self)
                }
                override func viewWillAppear(_ animated: Bool) {
@@ -84,11 +88,11 @@
                                                self?.player.play()
                                }
                                NotificationCenter.default.rx.notification(PlantGuideQuit_Noti).take(until: self.rx.deallocated).subscribe(onNext: {data in
                                NotificationCenter.default.rx.notification(PlantGuideQuit_Noti).take(until: self.rx.deallocated).subscribe(onNext: {[weak self]data in
                                                if data.object as? Bool == true{
                                                }
                                                self.dismiss(animated: true)
                                                self?.dismiss(animated: true)
                                }).disposed(by: disposeBag)
                }
@@ -101,13 +105,13 @@
                }
                @IBAction func customAction(_ sender: UIButton) {
                                PlanGuidePromptView.show { type in
                                PlanGuidePromptView.show {[weak self] type in
                                                switch type {
                                                                case .seeOther:
                                                                                let vc = PlanGuide_1_VC()
                                                                                self.jq_push(vc: vc)
                                                                                self?.jq_push(vc: vc)
                                                                case .toSeting:
                                                                                self.dismiss(animated: true) {
                                                                                self?.dismiss(animated: true) {
                                                                                                let vc = BackgroundVoiceVC()
                                                                                                vc.hidesBottomBarWhenPushed = true
                                                                                                JQ_currentNavigationController().pushViewController(vc)
@@ -115,4 +119,15 @@
                                                }
                                }
                }
    deinit{
        masterPlayer.clean()
    }
}
extension PlanGuideVC:PayMusicDelegate{
    func playState(_ state: PlayMusicState) {
    }
}
XQMuse/Root/Plans/PlanGuide_2_VC.swift
@@ -19,7 +19,7 @@
                @IBOutlet weak var btn_OnceInAWel: UIButton!
                private var questions = [String]()
                private var questionIndex = -1
                private var questionIndex = 0
                private var responseUserAnswerModel = ResponseUserAnswerModel()
XQMuse/Root/Plans/PlanGuide_3_VC.swift
@@ -57,7 +57,7 @@
                }
                @IBAction func nextAction(_ sender: UIButton) {
                                responseUserAnswerModel.tagsId = selectModels.map({"\($0.id)"}).joined(separator: ",")
        responseUserAnswerModel.tagIds = selectModels.map({"\($0.id)"}).joined(separator: ",")
                                Services.saveUserAnswers(responseUserAnswerModel).subscribe(onNext: { data in
                                                NotificationCenter.default.post(name: PlantGuideQuit_Noti, object: true)
                                }).disposed(by: disposeBag)
XQMuse/Root/ViewModel/RefreshModel.swift
@@ -181,7 +181,7 @@
                                                                                var new = self.dataSource.value?.list ?? []
                                                                                new.append(contentsOf: data.data?.list ?? [])
                                                                                var model = self.dataSource.value
                                                                                model!.list = new
                                                                                model?.list = new
                                                                                self.dataSource.accept(model)
                                                                                if data.data?.list.count == 0{
                                                                                                self.refreshSubject.onNext(.completedLoadWithNoMoreData)
XQMuse/SceneDelegate.swift
@@ -10,7 +10,7 @@
import JQTools
import AuthenticationServices
class SceneDelegate: UIResponder, UIWindowSceneDelegate {
class SceneDelegate: UIResponder, UIWindowSceneDelegate, WXApiDelegate{
                var window: UIWindow?
@@ -71,6 +71,44 @@
                                
                }
    func scene(_ scene: UIScene, openURLContexts URLContexts: Set<UIOpenURLContext>) {
        if URLContexts.first?.url.scheme == WeChatAPPID,let code = URLContexts.first?.url.jq_params?["code"]{
            DispatchQueue.main.async {
                hiddenHUD()
                let resp = SendAuthResp()
                resp.code = code
                WeChatTools.getAccessToken(resp) { model in
                    if let m = model{
                        WeChatTools.getUserInfo(access_token: m.access_token, openId: m.openid) { userInfoModel in
                            if let u = userInfoModel{
                                Services.loginByWechat(headImgUrl: u.headimgurl, nickname: u.nickname, sex: u.sex, wxOpenId: u.openid).subscribe(onNext: {data in
                                    if let model = data.data{
                                        sceneDelegate?.loginSuccess()
                                        JQ_currentViewController().dismiss(animated:true)
                                        UserViewModel.saveLoginInfo(model)
                                        Services.getUserInfo().subscribe(onNext: {data in
                                            if let model = data.data{
                                                UserViewModel.saveAvatarInfo(model)
                                            }
                                        }).disposed(by: JQ_disposeBag)
                                    }
                                }).disposed(by: JQ_disposeBag)
                            }else{
                                alertError(msg: "获取信息失败")
                            }
                        }
                    }
                }
            }
        }
    }
    func scene(_ scene: UIScene, continue userActivity: NSUserActivity) {
        WXApi.handleOpenUniversalLink(userActivity, delegate: self)
    }
                func sceneDidDisconnect(_ scene: UIScene) {
                                // Called as the scene is being released by the system.
                                // This occurs shortly after the scene enters the background, or when its session is discarded.
@@ -99,6 +137,13 @@
                                // to restore the scene back to its current state.
                }
    func onReq(_ req: BaseReq) {
    }
    func onResp(_ resp: BaseResp) {
    }
}
XQMuse/XQMuse.entitlements
@@ -6,5 +6,9 @@
    <array>
        <string>Default</string>
    </array>
    <key>com.apple.developer.associated-domains</key>
    <array>
        <string>webcredentials:app.xqzhihui.com/app/</string>
    </array>
</dict>
</plist>