3 次代碼提交 a255a4b0ea ... 15ddc697eb

作者 SHA1 備註 提交日期
  “HeShaoZe” 15ddc697eb fix:优化引导弹窗. 4 月之前
  “HeShaoZe” acf57da1ff fix:添加引导评论的接口 4 月之前
  “HeShaoZe” d59829b3b5 fix:添加埋点和引导用评价。 4 月之前
共有 36 個文件被更改,包括 2095 次插入13 次删除
  1. 二進制
      .DS_Store
  2. 36 4
      QuickSearchLocation.xcodeproj/project.pbxproj
  3. 78 0
      QuickSearchLocation.xcodeproj/xcshareddata/xcschemes/QuickSearchLocation.xcscheme
  4. 二進制
      QuickSearchLocation/Classes/.DS_Store
  5. 5 0
      QuickSearchLocation/Classes/Category/UIFont+Extension.swift
  6. 21 0
      QuickSearchLocation/Classes/Common/Model/QSLGoodKeysModel.swift
  7. 13 0
      QuickSearchLocation/Classes/Common/Model/QSLGoodModel.swift
  8. 34 0
      QuickSearchLocation/Classes/Common/Model/QSLGuideIsTriggeredModel.swift
  9. 2 0
      QuickSearchLocation/Classes/Common/Tool/QSLGravityManager.swift
  10. 246 0
      QuickSearchLocation/Classes/Common/Tool/QSLGuideusersToCommentManager.swift
  11. 117 0
      QuickSearchLocation/Classes/Common/Tool/QSLStatisticsUserTimeManager.swift
  12. 22 2
      QuickSearchLocation/Classes/Main/AppDelegate.swift
  13. 2 0
      QuickSearchLocation/Classes/Main/SceneDelegate.swift
  14. 12 0
      QuickSearchLocation/Classes/Network/QSLNetwork.swift
  15. 9 1
      QuickSearchLocation/Classes/Pages/QSLAdd/Controller/QSLAddController.swift
  16. 8 0
      QuickSearchLocation/Classes/Pages/QSLFriend/Controller/QSLFriendController.swift
  17. 60 0
      QuickSearchLocation/Classes/Pages/QSLHome/Controller/QSLHomeController.swift
  18. 6 0
      QuickSearchLocation/Classes/Pages/QSLMessage/QSLRequest/QSLRequestCell.swift
  19. 6 0
      QuickSearchLocation/Classes/Pages/QSLMessage/View/QSLMessageHeaderView.swift
  20. 29 0
      QuickSearchLocation/Classes/Pages/QSLRoad/Controller/QSLRoadController.swift
  21. 119 6
      QuickSearchLocation/Classes/Pages/QSLVip/Controller/QSLVipController.swift
  22. 68 0
      QuickSearchLocation/Classes/Pages/QSLVip/QSLInAppReviewmanager.swift
  23. 340 0
      QuickSearchLocation/Classes/Pages/QSLVip/View/QSLVipAlertView.swift
  24. 325 0
      QuickSearchLocation/Classes/Pages/QSLVip/View/QSLVipResultsAlertView.swift
  25. 422 0
      QuickSearchLocation/Classes/Pages/QSLVip/View/QSLVipResultsNoMemberAlertView.swift
  26. 9 0
      QuickSearchLocation/Macro/QSLApi.swift
  27. 40 0
      QuickSearchLocation/Macro/QSLGravityConst.swift
  28. 22 0
      QuickSearchLocation/Resources/Assets.xcassets/Vip/vip_comment_content_bg.imageset/Contents.json
  29. 二進制
      QuickSearchLocation/Resources/Assets.xcassets/Vip/vip_comment_content_bg.imageset/vip_comment_content_bg@2x.png
  30. 二進制
      QuickSearchLocation/Resources/Assets.xcassets/Vip/vip_comment_content_bg.imageset/vip_comment_content_bg@3x.png
  31. 22 0
      QuickSearchLocation/Resources/Assets.xcassets/Vip/vip_comment_give_thumb.imageset/Contents.json
  32. 二進制
      QuickSearchLocation/Resources/Assets.xcassets/Vip/vip_comment_give_thumb.imageset/vip_comment_give_thumb@2x.png
  33. 二進制
      QuickSearchLocation/Resources/Assets.xcassets/Vip/vip_comment_give_thumb.imageset/vip_comment_give_thumb@3x.png
  34. 22 0
      QuickSearchLocation/Resources/Assets.xcassets/Vip/vip_comment_sunlight.imageset/Contents.json
  35. 二進制
      QuickSearchLocation/Resources/Assets.xcassets/Vip/vip_comment_sunlight.imageset/vip_comment_sunlight@2x.png
  36. 二進制
      QuickSearchLocation/Resources/Assets.xcassets/Vip/vip_comment_sunlight.imageset/vip_comment_sunlight@3x.png

二進制
.DS_Store


+ 36 - 4
QuickSearchLocation.xcodeproj/project.pbxproj

@@ -121,6 +121,14 @@
 		FE9139C92DE6B018001A8E42 /* QSLVipMostGoodCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = FE9139C82DE6B018001A8E42 /* QSLVipMostGoodCell.swift */; };
 		FE94B4F42D23F09100D2B001 /* LoadingViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = FE94B4F32D23F09100D2B001 /* LoadingViewController.swift */; };
 		FEC010E72D9E8B06008B8B0A /* QSLSubscriptionModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = FEC010E62D9E8AFE008B8B0A /* QSLSubscriptionModel.swift */; };
+		FED298C42E37267100F1E0F0 /* QSLVipAlertView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FED298C32E37267100F1E0F0 /* QSLVipAlertView.swift */; };
+		FED298C62E38AB5500F1E0F0 /* QSLVipResultsAlertView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FED298C52E38AB5500F1E0F0 /* QSLVipResultsAlertView.swift */; };
+		FED298C82E38B51400F1E0F0 /* QSLVipResultsNoMemberAlertView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FED298C72E38B51400F1E0F0 /* QSLVipResultsNoMemberAlertView.swift */; };
+		FED298CA2E39C38400F1E0F0 /* QSLInAppReviewmanager.swift in Sources */ = {isa = PBXBuildFile; fileRef = FED298C92E39C38400F1E0F0 /* QSLInAppReviewmanager.swift */; };
+		FED298D02E3A2C1700F1E0F0 /* QSLStatisticsUserTimeManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = FED298CF2E3A2C1700F1E0F0 /* QSLStatisticsUserTimeManager.swift */; };
+		FED298D22E3B0EDD00F1E0F0 /* QSLGuideusersToCommentManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = FED298D12E3B0EDD00F1E0F0 /* QSLGuideusersToCommentManager.swift */; };
+		FED298D42E3B176500F1E0F0 /* QSLGuideIsTriggeredModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = FED298D32E3B176500F1E0F0 /* QSLGuideIsTriggeredModel.swift */; };
+		FED298D62E3B28D800F1E0F0 /* QSLGoodKeysModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = FED298D52E3B28D800F1E0F0 /* QSLGoodKeysModel.swift */; };
 		FEEB37CA2E28CC8F00BFFD7D /* QSAppleAdHandle.swift in Sources */ = {isa = PBXBuildFile; fileRef = FEEB37C92E28CC8F00BFFD7D /* QSAppleAdHandle.swift */; };
 		FEEB37CD2E28CD7A00BFFD7D /* QSWikiHandle.swift in Sources */ = {isa = PBXBuildFile; fileRef = FEEB37CC2E28CD7A00BFFD7D /* QSWikiHandle.swift */; };
 /* End PBXBuildFile section */
@@ -246,6 +254,14 @@
 		FE9139C82DE6B018001A8E42 /* QSLVipMostGoodCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QSLVipMostGoodCell.swift; sourceTree = "<group>"; };
 		FE94B4F32D23F09100D2B001 /* LoadingViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LoadingViewController.swift; sourceTree = "<group>"; };
 		FEC010E62D9E8AFE008B8B0A /* QSLSubscriptionModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QSLSubscriptionModel.swift; sourceTree = "<group>"; };
+		FED298C32E37267100F1E0F0 /* QSLVipAlertView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QSLVipAlertView.swift; sourceTree = "<group>"; };
+		FED298C52E38AB5500F1E0F0 /* QSLVipResultsAlertView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QSLVipResultsAlertView.swift; sourceTree = "<group>"; };
+		FED298C72E38B51400F1E0F0 /* QSLVipResultsNoMemberAlertView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QSLVipResultsNoMemberAlertView.swift; sourceTree = "<group>"; };
+		FED298C92E39C38400F1E0F0 /* QSLInAppReviewmanager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QSLInAppReviewmanager.swift; sourceTree = "<group>"; };
+		FED298CF2E3A2C1700F1E0F0 /* QSLStatisticsUserTimeManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QSLStatisticsUserTimeManager.swift; sourceTree = "<group>"; };
+		FED298D12E3B0EDD00F1E0F0 /* QSLGuideusersToCommentManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QSLGuideusersToCommentManager.swift; sourceTree = "<group>"; };
+		FED298D32E3B176500F1E0F0 /* QSLGuideIsTriggeredModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QSLGuideIsTriggeredModel.swift; sourceTree = "<group>"; };
+		FED298D52E3B28D800F1E0F0 /* QSLGoodKeysModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QSLGoodKeysModel.swift; sourceTree = "<group>"; };
 		FEEB37C92E28CC8F00BFFD7D /* QSAppleAdHandle.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QSAppleAdHandle.swift; sourceTree = "<group>"; };
 		FEEB37CC2E28CD7A00BFFD7D /* QSWikiHandle.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QSWikiHandle.swift; sourceTree = "<group>"; };
 /* End PBXFileReference section */
@@ -549,8 +565,10 @@
 				FE8360BA2D03002D00978E03 /* QSLMapPointModel.swift */,
 				FE8360BC2D068DCB00978E03 /* QSLMemberModel.swift */,
 				FE638AA12D096E6600858121 /* QSLGoodModel.swift */,
+				FED298D52E3B28D800F1E0F0 /* QSLGoodKeysModel.swift */,
 				FE638AA52D097EDD00858121 /* QSLOrderModel.swift */,
 				FE638AB22D0ACA4D00858121 /* QSLContactModel.swift */,
+				FED298D32E3B176500F1E0F0 /* QSLGuideIsTriggeredModel.swift */,
 			);
 			path = Model;
 			sourceTree = "<group>";
@@ -757,6 +775,7 @@
 				FE83607F2CF723EC00978E03 /* View */,
 				FE83607E2CF723E800978E03 /* Controller */,
 				FE638AA32D0978B100858121 /* QSLVipManager.swift */,
+				FED298C92E39C38400F1E0F0 /* QSLInAppReviewmanager.swift */,
 			);
 			path = QSLVip;
 			sourceTree = "<group>";
@@ -772,6 +791,9 @@
 		FE83607F2CF723EC00978E03 /* View */ = {
 			isa = PBXGroup;
 			children = (
+				FED298C32E37267100F1E0F0 /* QSLVipAlertView.swift */,
+				FED298C52E38AB5500F1E0F0 /* QSLVipResultsAlertView.swift */,
+				FED298C72E38B51400F1E0F0 /* QSLVipResultsNoMemberAlertView.swift */,
 			);
 			path = View;
 			sourceTree = "<group>";
@@ -838,6 +860,8 @@
 				FE638A9F2D082FC400858121 /* QSLLoading.swift */,
 				FE638ABA2D19631900858121 /* QSLGravityManager.swift */,
 				FE638AD32D1ABB9800858121 /* QSLJumpManager.swift */,
+				FED298CF2E3A2C1700F1E0F0 /* QSLStatisticsUserTimeManager.swift */,
+				FED298D12E3B0EDD00F1E0F0 /* QSLGuideusersToCommentManager.swift */,
 			);
 			path = Tool;
 			sourceTree = "<group>";
@@ -1007,8 +1031,10 @@
 				FE8360902CFFFAD600978E03 /* QSLAlertView.swift in Sources */,
 				FE8360A42D014EDA00978E03 /* QSLMessageHeaderView.swift in Sources */,
 				FE8360B32D02939600978E03 /* QSLSocketManager.swift in Sources */,
+				FED298C62E38AB5500F1E0F0 /* QSLVipResultsAlertView.swift in Sources */,
 				FE638AB92D195D5000858121 /* QSLGravityConst.swift in Sources */,
 				FE83609A2D004E3400978E03 /* QSLBaseManager.swift in Sources */,
+				FED298C82E38B51400F1E0F0 /* QSLVipResultsNoMemberAlertView.swift in Sources */,
 				FE3B5E9A2E2A3B92002616CD /* QSQuickLogonHandle.swift in Sources */,
 				04F33BD32BC67A18003E2111 /* UIViewController+Extension.swift in Sources */,
 				04B6B51A2BCCFDE700777EB4 /* Date+Extension.swift in Sources */,
@@ -1023,6 +1049,7 @@
 				FE83609C2D00534800978E03 /* QSLNotification.swift in Sources */,
 				04F33BDB2BC68C4E003E2111 /* QSLBaseController.swift in Sources */,
 				04F33BAA2BC6367C003E2111 /* ViewController.swift in Sources */,
+				FED298D62E3B28D800F1E0F0 /* QSLGoodKeysModel.swift in Sources */,
 				FE638AA42D0978B100858121 /* QSLVipManager.swift in Sources */,
 				04F33BE92BC69EA5003E2111 /* QSLConst.swift in Sources */,
 				FE8360B52D029BA800978E03 /* QSLMapMessageModel.swift in Sources */,
@@ -1036,9 +1063,11 @@
 				FE8360A72D017C4300978E03 /* QSLRequestController.swift in Sources */,
 				FE8360812CF723FA00978E03 /* QSLVipController.swift in Sources */,
 				04F33BD92BC6896F003E2111 /* UITabBarController+Extension.swift in Sources */,
+				FED298D42E3B176500F1E0F0 /* QSLGuideIsTriggeredModel.swift in Sources */,
 				04F33BCD2BC67486003E2111 /* UIView+Extension.swift in Sources */,
 				FE638AB02D0A8FF700858121 /* QSLContactAddAlertView.swift in Sources */,
 				FE8360932D003AA300978E03 /* QSLNetwork.swift in Sources */,
+				FED298C42E37267100F1E0F0 /* QSLVipAlertView.swift in Sources */,
 				FE8360B12D01BFE500978E03 /* QSLFriendRemarkAlertView.swift in Sources */,
 				FE638AD22D1AA6E800858121 /* QSLWebController.swift in Sources */,
 				FE8360A22D00814000978E03 /* QSLPopViewCell.swift in Sources */,
@@ -1066,6 +1095,7 @@
 				04B666C72BC8D7F30020BFBD /* QSLFriendAddAlertView.swift in Sources */,
 				FE83606B2CF5C73F00978E03 /* NSMutableAttributedString+Extension.swift in Sources */,
 				04F33BE72BC69318003E2111 /* QSLHomeController.swift in Sources */,
+				FED298D22E3B0EDD00F1E0F0 /* QSLGuideusersToCommentManager.swift in Sources */,
 				04F33BD52BC67CEB003E2111 /* Bundle+Extension.swift in Sources */,
 				04B666B82BC7BAFB0020BFBD /* UILabel+Extension.swift in Sources */,
 				FE8360AB2D01930600978E03 /* QSLMessageModel.swift in Sources */,
@@ -1081,6 +1111,7 @@
 				04F33BE12BC692C4003E2111 /* QSLMessageController.swift in Sources */,
 				FE8360982D0041F300978E03 /* QSLCacheManager.swift in Sources */,
 				FE8360AD2D01A04800978E03 /* QSLRequestModel.swift in Sources */,
+				FED298D02E3A2C1700F1E0F0 /* QSLStatisticsUserTimeManager.swift in Sources */,
 				04B6B5292BCE1D5C00777EB4 /* QSLMineFuncCollectionViewCell.swift in Sources */,
 				FEEB37CA2E28CC8F00BFFD7D /* QSAppleAdHandle.swift in Sources */,
 				FE638AB32D0ACA4D00858121 /* QSLContactModel.swift in Sources */,
@@ -1094,6 +1125,7 @@
 				FE8360A02D00813400978E03 /* QSLPopView.swift in Sources */,
 				04F33BCB2BC672E4003E2111 /* QSLConfig.swift in Sources */,
 				FE83607C2CF7140200978E03 /* QSLAddController.swift in Sources */,
+				FED298CA2E39C38400F1E0F0 /* QSLInAppReviewmanager.swift in Sources */,
 				FE8360782CF70CA200978E03 /* NSAttributedString+Extension.swift in Sources */,
 				04F33BD12BC6792D003E2111 /* UIVisualEffectView+Extension.swift in Sources */,
 				FE8360B92D02F9B500978E03 /* QSLHomeCallOutView.swift in Sources */,
@@ -1262,7 +1294,7 @@
 				ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
 				CODE_SIGN_IDENTITY = "Apple Development";
 				CODE_SIGN_STYLE = Automatic;
-				CURRENT_PROJECT_VERSION = 22;
+				CURRENT_PROJECT_VERSION = 23;
 				DEVELOPMENT_TEAM = Q364C8K9BL;
 				ENABLE_USER_SCRIPT_SANDBOXING = NO;
 				FRAMEWORK_SEARCH_PATHS = (
@@ -1286,7 +1318,7 @@
 					"$(inherited)",
 					"@executable_path/Frameworks",
 				);
-				MARKETING_VERSION = 1.2.4;
+				MARKETING_VERSION = 1.2.5;
 				PRODUCT_BUNDLE_IDENTIFIER = com.manbu.shouji;
 				PRODUCT_NAME = "$(TARGET_NAME)";
 				PROVISIONING_PROFILE_SPECIFIER = "";
@@ -1306,7 +1338,7 @@
 				ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
 				CODE_SIGN_IDENTITY = "Apple Development";
 				CODE_SIGN_STYLE = Automatic;
-				CURRENT_PROJECT_VERSION = 22;
+				CURRENT_PROJECT_VERSION = 23;
 				DEVELOPMENT_TEAM = Q364C8K9BL;
 				ENABLE_USER_SCRIPT_SANDBOXING = NO;
 				FRAMEWORK_SEARCH_PATHS = (
@@ -1330,7 +1362,7 @@
 					"$(inherited)",
 					"@executable_path/Frameworks",
 				);
-				MARKETING_VERSION = 1.2.4;
+				MARKETING_VERSION = 1.2.5;
 				PRODUCT_BUNDLE_IDENTIFIER = com.manbu.shouji;
 				PRODUCT_NAME = "$(TARGET_NAME)";
 				PROVISIONING_PROFILE_SPECIFIER = "";

+ 78 - 0
QuickSearchLocation.xcodeproj/xcshareddata/xcschemes/QuickSearchLocation.xcscheme

@@ -0,0 +1,78 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<Scheme
+   LastUpgradeVersion = "1610"
+   version = "1.7">
+   <BuildAction
+      parallelizeBuildables = "YES"
+      buildImplicitDependencies = "YES"
+      buildArchitectures = "Automatic">
+      <BuildActionEntries>
+         <BuildActionEntry
+            buildForTesting = "YES"
+            buildForRunning = "YES"
+            buildForProfiling = "YES"
+            buildForArchiving = "YES"
+            buildForAnalyzing = "YES">
+            <BuildableReference
+               BuildableIdentifier = "primary"
+               BlueprintIdentifier = "04F33BA12BC6367C003E2111"
+               BuildableName = "QuickSearchLocation.app"
+               BlueprintName = "QuickSearchLocation"
+               ReferencedContainer = "container:QuickSearchLocation.xcodeproj">
+            </BuildableReference>
+         </BuildActionEntry>
+      </BuildActionEntries>
+   </BuildAction>
+   <TestAction
+      buildConfiguration = "Debug"
+      selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
+      selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
+      shouldUseLaunchSchemeArgsEnv = "YES"
+      shouldAutocreateTestPlan = "YES">
+   </TestAction>
+   <LaunchAction
+      buildConfiguration = "Debug"
+      selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
+      selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
+      launchStyle = "0"
+      useCustomWorkingDirectory = "NO"
+      ignoresPersistentStateOnLaunch = "NO"
+      debugDocumentVersioning = "YES"
+      debugServiceExtension = "internal"
+      allowLocationSimulation = "YES">
+      <BuildableProductRunnable
+         runnableDebuggingMode = "0">
+         <BuildableReference
+            BuildableIdentifier = "primary"
+            BlueprintIdentifier = "04F33BA12BC6367C003E2111"
+            BuildableName = "QuickSearchLocation.app"
+            BlueprintName = "QuickSearchLocation"
+            ReferencedContainer = "container:QuickSearchLocation.xcodeproj">
+         </BuildableReference>
+      </BuildableProductRunnable>
+   </LaunchAction>
+   <ProfileAction
+      buildConfiguration = "Release"
+      shouldUseLaunchSchemeArgsEnv = "YES"
+      savedToolIdentifier = ""
+      useCustomWorkingDirectory = "NO"
+      debugDocumentVersioning = "YES">
+      <BuildableProductRunnable
+         runnableDebuggingMode = "0">
+         <BuildableReference
+            BuildableIdentifier = "primary"
+            BlueprintIdentifier = "04F33BA12BC6367C003E2111"
+            BuildableName = "QuickSearchLocation.app"
+            BlueprintName = "QuickSearchLocation"
+            ReferencedContainer = "container:QuickSearchLocation.xcodeproj">
+         </BuildableReference>
+      </BuildableProductRunnable>
+   </ProfileAction>
+   <AnalyzeAction
+      buildConfiguration = "Debug">
+   </AnalyzeAction>
+   <ArchiveAction
+      buildConfiguration = "Release"
+      revealArchiveInOrganizer = "YES">
+   </ArchiveAction>
+</Scheme>

二進制
QuickSearchLocation/Classes/.DS_Store


+ 5 - 0
QuickSearchLocation/Classes/Category/UIFont+Extension.swift

@@ -94,4 +94,9 @@ extension UIFont {
         let scaleSize = ofSize.rpx
         return UIFont.systemFont(ofSize: scaleSize, weight: Weight)
     }
+    
+    func withTraits(traits: UIFontDescriptor.SymbolicTraits) -> UIFont {
+        let descriptor = fontDescriptor.withSymbolicTraits(traits)
+        return UIFont(descriptor: descriptor!, size: 0)
+    }
 }

+ 21 - 0
QuickSearchLocation/Classes/Common/Model/QSLGoodKeysModel.swift

@@ -0,0 +1,21 @@
+//
+//  QSLGoodKeysModel.swift
+//  QuickSearchLocation
+//
+//  Created by Destiny on 2025/7/31.
+//
+
+import MoyaMapper
+import SwiftyJSON
+
+struct QSLGoodKeysModel: Modelable {
+    ///关键字
+    var key: String = ""
+    ///值
+    var value: String = ""
+    
+    mutating func mapping(_ json: SwiftyJSON.JSON) {
+        self.key = json["key"].stringValue
+        self.value = json["value"].stringValue
+    }
+}

+ 13 - 0
QuickSearchLocation/Classes/Common/Model/QSLGoodModel.swift

@@ -38,8 +38,21 @@ struct QSLGoodModel: Modelable {
     
     var subscribable : Int = 0
     
+    var showText: Bool = false
+    
+    ///感谢支持,您的套餐会员天数将额外增加 %day 天
+    var text : String = ""
+    
+    ///额外信息填充内容
+    var keys : QSLGoodKeysModel = QSLGoodKeysModel()
+    
+    
     mutating func mapping(_ json: JSON) {
         self.goodId = json["id"].intValue
         self.content = json["description"].stringValue
+        
+        var keysModel = QSLGoodKeysModel()
+        keysModel.mapping(json["key"]) // 假设 JSON 中嵌套字段名为 "keys"
+        self.keys = keysModel
     }
 }

+ 34 - 0
QuickSearchLocation/Classes/Common/Model/QSLGuideIsTriggeredModel.swift

@@ -0,0 +1,34 @@
+//
+//  QSLGuideIsTriggeredModel.swift
+//  QuickSearchLocation
+//
+//  Created by Destiny on 2025/7/31.
+//
+
+import Foundation
+import MoyaMapper
+import SwiftyJSON
+
+struct QSLGuideIsTriggeredModel : Modelable {
+    
+    ///用户是否弹窗过(终身一次)
+    var triggerStatus : Bool = false
+    
+    ///当前是否弹窗
+    var isTrigger : Bool = false
+    
+    ///会员商品level 100:日卡 700:周卡 3100:月卡 9200:季卡 36600:年卡 3660000:终身会员
+    var level : Int = 0
+    
+    ///会员额外天数
+    var extraMemberDays : Int = 0
+    
+    //根据登记返回天数
+    func returnDaysBasedOnRegistration() -> Int {
+        return self.level / 100
+    }
+    
+    mutating func mapping(_ json: SwiftyJSON.JSON) {
+        
+    }
+}

+ 2 - 0
QuickSearchLocation/Classes/Common/Tool/QSLGravityManager.swift

@@ -55,6 +55,8 @@ class QSLGravityManager {
             QSLBaseManager.shared.initPayCheck()
         })
         
+        //开始统计时长
+        QSLStatisticsUserTimeManager.shared.startTracking()
     }
     
 }

+ 246 - 0
QuickSearchLocation/Classes/Common/Tool/QSLGuideusersToCommentManager.swift

@@ -0,0 +1,246 @@
+//
+//  QSLGuideusersToCommentManager.swift
+//  QuickSearchLocation
+//
+//  Created by Destiny on 2025/7/31.
+//
+
+import Foundation
+import UIKit
+
+enum QSLGuideusersToCommentType : Int{
+    case member //会员
+    case nonMember // 非会员
+}
+class QSLGuideusersToCommentManager: NSObject {
+    
+    static let commentShare = QSLGuideusersToCommentManager()
+
+    var guideGobalModel : QSLGuideIsTriggeredModel = QSLGuideIsTriggeredModel()
+    
+    var commentType : QSLGuideusersToCommentType = .member
+    
+    //管理处理是否触发好评引导弹窗
+    func manageWhetherTriggerPopUpWindow(_ showType : QSLGuideusersToCommentType) {
+        //print("showTypesdfsdfs---\(showType)")
+        QSLNetwork().request(.guideIsTriggered(dict: [String : Any]())) { response in
+            //print("responsesfsdfsf-----\(response)")
+            let guideIsModel : QSLGuideIsTriggeredModel = response.mapObject(QSLGuideIsTriggeredModel.self, modelKey: "data")
+            self.commentType = showType
+            self.guideGobalModel = guideIsModel
+            if (!guideIsModel.triggerStatus && guideIsModel.isTrigger) {
+                if  showType == .member {
+                    DispatchQueue.main.async {
+                        self.memberPositiveReviewPopWindow()
+                    }
+                } else {
+                    DispatchQueue.main.async {
+                        self.noMemberPositiveReviewPopWindow()
+                    }
+                }
+            }
+            
+        } fail: { code, msg in
+        }
+    }
+    
+    ///领取好评引导奖励请求
+    func requestForReceivingGoodReviewGuidance() {
+        QSLNetwork().request(.guideReceiveReward(dict: [String : Any]())) { response in
+            if self.commentType == .member {
+                DispatchQueue.main.async {
+                    self.popUpWindowForMemberReview()
+                }
+            } else {
+                DispatchQueue.main.async {
+                    self.popUpWindowForNonMemberReviews()
+                }
+            }
+        } fail: { code, msg in
+        }
+
+    }
+}
+
+
+//管理各种类型的痰喘
+extension QSLGuideusersToCommentManager {
+    
+    ///会员的好评弹窗
+    @MainActor func memberPositiveReviewPopWindow() {
+        // 创建深灰色文本样式
+        let darkGrayAttributes: [NSAttributedString.Key: Any] = [
+            .foregroundColor: UIColor(red: 51/255.0, green: 51/255.0, blue: 51/255.0, alpha: 1.0),
+            .font: UIFont(name: "Noto Sans SC", size: 20)?.withTraits(traits: .traitBold) ?? UIFont.systemFont(ofSize: 20, weight: .black),
+            .paragraphStyle: {
+                let paragraphStyle = NSMutableParagraphStyle()
+                paragraphStyle.alignment = .center
+                return paragraphStyle
+            }(),
+            .kern: -1
+        ]
+        
+        // 创建绿色文本样式
+        let greenAttributes: [NSAttributedString.Key: Any] = [
+            .foregroundColor: UIColor(red: 17/255.0, green: 186/255.0, blue: 152/255.0, alpha: 1.0),
+            .font: UIFont(name: "Noto Sans SC", size: 20)?.withTraits(traits: .traitBold) ?? UIFont.systemFont(ofSize: 20, weight: .black),
+            .paragraphStyle: {
+                let paragraphStyle = NSMutableParagraphStyle()
+                paragraphStyle.alignment = .center
+                return paragraphStyle
+            }(),
+            .kern: -1
+        ]
+        
+        let inputtr = NSMutableAttributedString()
+        let titleOneAttr = NSAttributedString(string: "五星好评,", attributes: darkGrayAttributes)
+        let titleTwoAttr = NSAttributedString(string: "多送\(self.guideGobalModel.extraMemberDays)天会员", attributes: greenAttributes)
+        inputtr.append(titleOneAttr)
+        inputtr.append(titleTwoAttr)
+        
+        if let currentWindow = UIApplication.keyWindow {
+            QSLVipAlertView.alert(view: currentWindow, title: "", titleAttring: inputtr, content: "你的一条五星好评是我们前进的动力", isOneBtn: true, oneBtnText: "立即好评", oneBtnClosure:  { [weak self] in
+                // 同步调用
+                QSLInAppReviewmanager.requestReview()
+                
+                DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
+                    self?.requestForReceivingGoodReviewGuidance()
+                }
+            })
+        }
+    }
+    
+    ///非会员的好评弹窗
+    @MainActor func noMemberPositiveReviewPopWindow() {
+        // 创建深灰色文本样式
+        let darkGrayAttributes: [NSAttributedString.Key: Any] = [
+            .foregroundColor: UIColor(red: 51/255.0, green: 51/255.0, blue: 51/255.0, alpha: 1.0),
+            .font: UIFont(name: "Noto Sans SC", size: 20)?.withTraits(traits: .traitBold) ?? UIFont.systemFont(ofSize: 20, weight: .black),
+            .paragraphStyle: {
+                let paragraphStyle = NSMutableParagraphStyle()
+                paragraphStyle.alignment = .center
+                return paragraphStyle
+            }(),
+            .kern: -1
+        ]
+
+        let inputtr = NSMutableAttributedString()
+        let titleOneAttr = NSAttributedString(string: "给我们一个好评呗~", attributes: darkGrayAttributes)
+        inputtr.append(titleOneAttr)
+        
+        if let currentWindow = UIApplication.keyWindow {
+            QSLVipAlertView.alert(view: currentWindow, title: "", titleAttring: inputtr, content: "我们将回馈用户更多的优惠福利", isOneBtn: true, oneBtnText: "立即好评", oneBtnClosure:  { [weak self] in
+                
+                // 同步调用
+                QSLInAppReviewmanager.requestReview()
+                
+                // 延迟1秒执行
+                DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
+                    self?.requestForReceivingGoodReviewGuidance()
+                }
+                //self?.requestAddFri()
+            })
+        }
+    }
+    
+    ///会员好评的结果弹窗
+    @MainActor func popUpWindowForMemberReview() {
+        // 创建深灰色文本样式
+        let darkGrayAttributes: [NSAttributedString.Key: Any] = [
+            .foregroundColor: UIColor(red: 51/255.0, green: 51/255.0, blue: 51/255.0, alpha: 1.0),
+            .font: UIFont(name: "Noto Sans SC", size: 20)?.withTraits(traits: .traitBold) ?? UIFont.systemFont(ofSize: 20, weight: .black),
+            .paragraphStyle: {
+                let paragraphStyle = NSMutableParagraphStyle()
+                paragraphStyle.alignment = .center
+                return paragraphStyle
+            }(),
+            .kern: -1
+        ]
+
+        // 创建绿色文本样式
+        let greenAttributes: [NSAttributedString.Key: Any] = [
+            .foregroundColor: UIColor(red: 17/255.0, green: 186/255.0, blue: 152/255.0, alpha: 1.0),
+            .font: UIFont(name: "Noto Sans SC", size: 28)?.withTraits(traits: .traitBold) ?? UIFont.systemFont(ofSize: 28, weight: .black),
+            .paragraphStyle: {
+                let paragraphStyle = NSMutableParagraphStyle()
+                paragraphStyle.alignment = .center
+                return paragraphStyle
+            }(),
+            .kern: -1
+        ]
+
+        let inputtr = NSMutableAttributedString()
+        let titleOneAttr = NSAttributedString(string: "你已成功增加", attributes: darkGrayAttributes)
+        let titleTwoAttr = NSAttributedString(string: " \(self.guideGobalModel.extraMemberDays) ", attributes: greenAttributes)
+        let titleThreeAttr = NSAttributedString(string: "天会员", attributes: darkGrayAttributes)
+        inputtr.append(titleOneAttr)
+        inputtr.append(titleTwoAttr)
+        inputtr.append(titleThreeAttr)
+        
+        
+        if let currentWindow = UIApplication.keyWindow {
+            QSLVipResultsAlertView.alert(view: currentWindow, title: "", titleAttring: inputtr, content: "恭喜你,领取成功!", isOneBtn: true, oneBtnText: "我知道了", oneBtnClosure:  { [weak self] in
+                //self?.requestAddFri()
+            })
+        }
+
+    }
+    
+    ///非会员好评的结果弹窗
+    @MainActor func popUpWindowForNonMemberReviews() {
+        ///标题
+        let titleDarkGrayAttributes: [NSAttributedString.Key: Any] = [
+            .foregroundColor: UIColor(red: 51/255.0, green: 51/255.0, blue: 51/255.0, alpha: 1.0),
+            .font: UIFont(name: "Noto Sans SC", size: 20)?.withTraits(traits: .traitBold) ?? UIFont.systemFont(ofSize: 20, weight: .black),
+            .paragraphStyle: {
+                let paragraphStyle = NSMutableParagraphStyle()
+                paragraphStyle.alignment = .center
+                return paragraphStyle
+            }(),
+            .kern: -1
+        ]
+        
+        // 创建深灰色文本样式
+        let darkGrayAttributes: [NSAttributedString.Key: Any] = [
+            .foregroundColor: UIColor(red: 255/255.0, green: 230/255.0, blue: 192/255.0, alpha: 1.0),
+            .font: UIFont(name: "Noto Sans SC", size: 16)?.withTraits(traits: .traitBold) ?? UIFont.systemFont(ofSize: 20, weight: .black),
+            .paragraphStyle: {
+                let paragraphStyle = NSMutableParagraphStyle()
+                paragraphStyle.alignment = .center
+                return paragraphStyle
+            }(),
+            .kern: -1
+        ]
+        
+        
+        // 创建绿色文本样式
+        let greenAttributes: [NSAttributedString.Key: Any] = [
+            .foregroundColor: UIColor(red: 255/255.0, green: 230/255.0, blue: 192/255.0, alpha: 1.0),
+            .font: UIFont(name: "Noto Sans SC", size: 20)?.withTraits(traits: .traitBold) ?? UIFont.systemFont(ofSize: 28, weight: .black),
+            .paragraphStyle: {
+                let paragraphStyle = NSMutableParagraphStyle()
+                paragraphStyle.alignment = .center
+                return paragraphStyle
+            }(),
+            .kern: -1
+        ]
+
+        let inputtr = NSMutableAttributedString()
+        let titleOneAttr = NSAttributedString(string: "感谢支持~", attributes: titleDarkGrayAttributes)
+        inputtr.append(titleOneAttr)
+        
+        let contentAtter = NSMutableAttributedString()
+        let contentAtterOne = NSAttributedString(string: "会员套餐体验", attributes: darkGrayAttributes)
+        contentAtter.append(contentAtterOne)
+        let contentAtterTwo = NSAttributedString(string: " \(self.guideGobalModel.returnDaysBasedOnRegistration())+\(self.guideGobalModel.extraMemberDays) ", attributes: greenAttributes)
+        contentAtter.append(contentAtterTwo)
+        let contentAtterTherr = NSAttributedString(string: "天", attributes: darkGrayAttributes)
+        contentAtter.append(contentAtterTherr)
+        
+        if let currentWindow = UIApplication.keyWindow {
+            QSLVipResultsNoMemberAlertView.alert(view: currentWindow, title: "", titleAttring: inputtr, content: "已解锁会员套餐体验7+3福利套餐",bottomContentAttring: contentAtter, isOneBtn: true, oneBtnText: "立即查看", oneBtnClosure:  { [weak self] in
+                QSLJumpManager.shared.pushToVip(type: .guideComments)
+            })
+        }
+    }
+}

+ 117 - 0
QuickSearchLocation/Classes/Common/Tool/QSLStatisticsUserTimeManager.swift

@@ -0,0 +1,117 @@
+//
+//  QSLStatisticsUserTimeManager.swift
+//  QuickSearchLocation
+//
+//  Created by Destiny on 2025/7/30.
+//
+
+import Foundation
+import UIKit
+import GravityEngineSDK
+
+class QSLStatisticsUserTimeManager {
+    static let shared = QSLStatisticsUserTimeManager()
+    private let userDefaults = UserDefaults.standard
+    private var backgroundTaskID: UIBackgroundTaskIdentifier?
+    private var timer: Timer?
+    private var sessionStartTime: Date?
+    
+    // MARK: - 键名常量
+    private struct Keys {
+        static let totalUsage = "GETotalUsageTime"
+        static let lastUploadTime = "GELastUploadTime"
+    }
+    
+    // 累计使用时长(秒)
+    private var totalUsageTime: TimeInterval {
+        get { userDefaults.double(forKey: Keys.totalUsage) }
+        set { userDefaults.set(newValue, forKey: Keys.totalUsage) }
+    }
+    
+    // MARK: - 生命周期监听
+    func startTracking() {
+        NotificationCenter.default.addObserver(self,
+            selector: #selector(appDidBecomeActive),
+            name: UIApplication.didBecomeActiveNotification,
+            object: nil)
+        
+        NotificationCenter.default.addObserver(self,
+            selector: #selector(appWillResignActive),
+            name: UIApplication.willResignActiveNotification,
+            object: nil)
+        
+        NotificationCenter.default.addObserver(
+            self,
+            selector: #selector(handleTrackResult),
+            name: Notification.Name("GravityEngineTrackResult"),
+            object: nil
+        )
+    }
+    
+    @objc func handleTrackResult()  {
+        print("数据商城成功----")
+    }
+    
+    @objc private func appDidBecomeActive() {
+        sessionStartTime = Date()
+        startPeriodicUpload()
+    }
+    
+    @objc private func appWillResignActive() {
+        saveCurrentSession()
+        beginBackgroundTask()
+    }
+    
+    // MARK: - 数据记录逻辑
+    private func saveCurrentSession() {
+        guard let start = sessionStartTime else { return }
+        totalUsageTime += Date().timeIntervalSince(start)
+        sessionStartTime = nil
+    }
+    
+    // MARK: - 定期上传
+    private func startPeriodicUpload() {
+        // 每隔5分钟检查上传(与SDK的上传间隔分开)
+        timer = Timer.scheduledTimer(withTimeInterval: 300, repeats: true) { [weak self] _ in
+            self?.uploadUsageData()
+        }
+    }
+    
+    private func uploadUsageData() {
+        saveCurrentSession()
+        
+        let properties: [String: Any] = [
+            "total_usage_seconds": totalUsageTime,
+            "last_upload_time": Date().timeIntervalSince1970
+        ]
+        
+        // 通过GravityEngine上报事件
+        gravityInstance?.track(QSLGravityConst.usage_collect_accumulatedTime, properties: properties)
+        print("时长上报成功")
+        self.totalUsageTime = 0  // 重置累计时长
+        self.userDefaults.set(Date().timeIntervalSince1970, forKey: Keys.lastUploadTime)
+        /*GravityEngine.shared.track("app_usage", properties: properties) { success, error in
+            if success {
+                print("时长上报成功")
+                self.totalUsageTime = 0  // 重置累计时长
+                self.userDefaults.set(Date().timeIntervalSince1970, forKey: Keys.lastUploadTime)
+            } else {
+                print("上报失败: \(error?.localizedDescription ?? "")")
+            }
+        }*/
+    }
+    
+    // MARK: - 后台任务
+    private func beginBackgroundTask() {
+        backgroundTaskID = UIApplication.shared.beginBackgroundTask { [weak self] in
+            self?.endBackgroundTask()
+        }
+    }
+    
+    private func endBackgroundTask() {
+        if let taskID = backgroundTaskID {
+            UIApplication.shared.endBackgroundTask(taskID)
+            backgroundTaskID = .invalid
+        }
+    }
+}

+ 22 - 2
QuickSearchLocation/Classes/Main/AppDelegate.swift

@@ -18,7 +18,8 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
         Thread.sleep(forTimeInterval: 1)
         IQKeyboardManager.shared.enable = true
         AMapServices.shared().apiKey = QSLConfig.MapKey
-        
+        //启动埋点
+        managerAppOnlyLaunch()
         return true
     }
 
@@ -31,6 +32,25 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
     func application(_ application: UIApplication, didDiscardSceneSessions sceneSessions: Set<UISceneSession>) {
     }
 
-
+    //管理app启动埋点
+    func managerAppOnlyLaunch() {
+        
+        guard UserDefaults.standard.string(forKey: "MANAGER_APP_ONLY_LAUNCH") != nil else {
+            UserDefaults.standard.set("YES", forKey: "MANAGER_APP_ONLY_LAUNCH")
+            UserDefaults.standard.synchronize()
+            //只有app第一次启动才会埋点
+            gravityInstance?.track(QSLGravityConst.app_launch, properties: ["id": 02001])
+            return
+        }
+    }
+    
+    // 当 App 即将终止(退出)时调用
+    func applicationWillTerminate(_ application: UIApplication) {
+        print("App 即将退出")
+        // 仅在 App 被用户主动退出或系统正常终止时触发(强制杀死进程时可能不调用)
+        // 可在此做最后的数据保存(操作需快速完成,系统可能限制时间)
+        ///埋点app退出
+        gravityInstance?.track(QSLGravityConst.app_exit, properties: ["id": 02002])
+    }
 }
 

+ 2 - 0
QuickSearchLocation/Classes/Main/SceneDelegate.swift

@@ -26,6 +26,8 @@ class SceneDelegate: UIResponder, UIWindowSceneDelegate {
     func sceneDidBecomeActive(_ scene: UIScene) {
         // Called when the scene has moved from an inactive state to an active state.
         // Use this method to restart any tasks that were paused (or not yet started) when the scene was inactive.
+        ///判断要不要弹引导用户去评价
+        QSLGuideusersToCommentManager.commentShare.manageWhetherTriggerPopUpWindow(QSLGuideusersToCommentType.nonMember)
     }
 
     func sceneWillResignActive(_ scene: UIScene) {

+ 12 - 0
QuickSearchLocation/Classes/Network/QSLNetwork.swift

@@ -51,6 +51,8 @@ enum QSLNetworkAPI {
     case contactMaydayAll(dict: [String: Any])
     case deviceInfoUpload(dict: [String: Any])
     case loginOneclick(dict: [String: Any])
+    case guideIsTriggered(dict: [String : Any])
+    case guideReceiveReward(dict: [String : Any])
 }
 
 extension QSLNetworkAPI: TargetType {
@@ -97,6 +99,8 @@ extension QSLNetworkAPI: TargetType {
         case .contactMaydayAll: return QSLApi.contact_mayday_all
         case .deviceInfoUpload: return QSLApi.device_info_upload
         case .loginOneclick: return QSLApi.login_oneclick
+        case .guideIsTriggered: return QSLApi.guide_is_triggered
+        case .guideReceiveReward: return QSLApi.guide_receisve_reward
         }
     }
     
@@ -249,6 +253,14 @@ extension QSLNetworkAPI: TargetType {
             for (key, value) in Dict {
                 parameters[key] = value
             }
+        case let .guideIsTriggered(Dict):
+            for (key, value) in Dict {
+                parameters[key] = value
+            }
+        case let .guideReceiveReward(Dict):
+            for (key, value) in Dict {
+                parameters[key] = value
+            }
         }
         debugPrint(parameters)
         return .requestParameters(parameters: parameters, encoding: JSONEncoding.default)

+ 9 - 1
QuickSearchLocation/Classes/Pages/QSLAdd/Controller/QSLAddController.swift

@@ -221,9 +221,17 @@ extension QSLAddController {
         QSLNetwork().request(.requestSend(dict: ["phone": phone])) { response in
             
             self.view.toast(text: "已发送好友请求")
+            if QSLBaseManager.shared.isVip() {
+                ///输入手机号添加成功
+                gravityInstance?.track(QSLGravityConst.vip_friend_add_success_phone, properties: ["id": 04003])
+            }
+
         } fail: { code, error in
             self.view.toast(text: error)
-            
+            if QSLBaseManager.shared.isVip() {
+                ///输入手机号添加失败
+                gravityInstance?.track(QSLGravityConst.vip_friend_add_fail_phone, properties: ["id": 04004])
+            }
             switch code {
             case 1102:
                 // 该好友已在好友列表

+ 8 - 0
QuickSearchLocation/Classes/Pages/QSLFriend/Controller/QSLFriendController.swift

@@ -106,6 +106,14 @@ extension QSLFriendController {
     
     @objc func addButtonAction() {
         
+        if QSLBaseManager.shared.isVip() {
+            ///点击添加好友埋点
+            gravityInstance?.track(QSLGravityConst.vip_friend_click_add, properties: ["id": 04001])
+        } else {
+            ///点击添加好友埋点
+            gravityInstance?.track(QSLGravityConst.friend_click_add, properties: ["id": 04002])
+        }
+        
         QSLJumpManager.shared.pushToAdd(type: .friend)
     }
     

+ 60 - 0
QuickSearchLocation/Classes/Pages/QSLHome/Controller/QSLHomeController.swift

@@ -19,6 +19,9 @@ class QSLHomeController: QSLBaseController {
     
     var personalModel: QSLUserModel = QSLUserModel()
     
+    ///判断是不是第一次定位成功
+    var isFirstLocatScuess : Bool = true
+    
 //    var friendList: [QSLUserModel] = [QSLUserModel]()
     
     override func viewDidLoad() {
@@ -36,6 +39,20 @@ class QSLHomeController: QSLBaseController {
         NotificationCenter.default.addObserver(self, selector: #selector(loadData), name: QSLNotification.QSLRefreshFriend, object: nil)
         NotificationCenter.default.addObserver(self, selector: #selector(loadData), name: QSLNotification.QSLRefreshRequest, object: nil)
         NotificationCenter.default.addObserver(self, selector: #selector(requestVip), name: QSLNotification.QSLRefreshMember, object: nil)
+        
+        //处理第一次进入首页定位
+        firstEnterLocationHomepage()
+    }
+    
+    //处理第一次进入首页定位
+    func firstEnterLocationHomepage() {
+        guard UserDefaults.standard.string(forKey: "FIRST_ENTER_LOCATION_HOMEPAGE") != nil else {
+            UserDefaults.standard.set("YES", forKey: "FIRST_ENTER_LOCATION_HOMEPAGE")
+            UserDefaults.standard.synchronize()
+            ///第一次进入埋点
+            gravityInstance?.track(QSLGravityConst.location_enter_first_homepage, properties: ["id": 03005])
+            return
+        }
     }
     
     /// 高德地图
@@ -346,6 +363,12 @@ extension QSLHomeController: MAMapViewDelegate, AMapLocationManagerDelegate {
     // 持续定位
     func amapLocationManager(_ manager: AMapLocationManager!, didUpdate location: CLLocation!, reGeocode: AMapLocationReGeocode!) {
         
+        if self.isFirstLocatScuess {
+            self.isFirstLocatScuess = false
+            //始终允许定位成功
+            gravityInstance?.track(QSLGravityConst.location_success_always, properties: ["id": 03003])
+        }
+        
         // 获取电话和名字
         self.personalModel = QSLBaseManager.shared.userModel
         
@@ -463,6 +486,43 @@ extension QSLHomeController: MAMapViewDelegate, AMapLocationManagerDelegate {
         
         return nil
     }
+    //@brief 定位权限状态改变时回调函数。注意:iOS13及之前版本回调
+    // 高德地图权限变化回调
+      func amapLocationManager(_ manager: AMapLocationManager, didChangeAuthorization status: CLAuthorizationStatus) {
+         //print("高德地图定位权限变化: \(status.rawValue)")
+          
+          switch status {
+          case .authorizedAlways, .authorizedWhenInUse:
+              //print("定位权限已授权")
+              //支付成功埋点
+              gravityInstance?.track(QSLGravityConst.location_allow_permission, properties: ["id": 03001])
+          case .denied:
+              //print("定位权限被拒绝")
+              //拒绝定位权限
+              gravityInstance?.track(QSLGravityConst.location_deny_permission, properties: ["id": 03002])
+          default:
+              break
+          }
+      }
+      
+      // 系统定位权限变化回调
+      func amapLocationManager(_ manager: AMapLocationManager, locationManagerDidChangeAuthorization locationManager: CLLocationManager) {
+          if #available(iOS 14.0, *) {
+              let status = locationManager.authorizationStatus
+              // 统一处理权限变化
+              amapLocationManager(manager, didChangeAuthorization: status)
+              //print("系统定位权限变化: \(status.rawValue)")
+          } else {
+              // Fallback on earlier versions
+          }
+      }
+      
+      // 定位结果回调
+      func amapLocationManager(_ manager: AMapLocationManager, didFailWithError error: Error) {
+          print("定位失败: \(error.localizedDescription)")
+          gravityInstance?.track(QSLGravityConst.location_fail_always, properties: ["id": 03004])
+      }
+    
 }
 
 // MARK: - 设置WebSocket

+ 6 - 0
QuickSearchLocation/Classes/Pages/QSLMessage/QSLRequest/QSLRequestCell.swift

@@ -87,6 +87,9 @@ class QSLRequestCell: UITableViewCell {
     
     @objc func refuseBtnAction() {
         
+        ///拒绝好友申请埋点
+        gravityInstance?.track(QSLGravityConst.friend_reject_request, properties: ["id": 04006])
+        
         if let model = self.model {
             delegate?.refuseBtnAction(model: model)
         }
@@ -94,6 +97,9 @@ class QSLRequestCell: UITableViewCell {
     
     @objc func agreeBtnAction() {
         
+        ///拒绝好友申请埋点
+        gravityInstance?.track(QSLGravityConst.friend_agree_request, properties: ["id": 04005])
+        
         if let model = self.model {
             delegate?.accpetBtnAction(model: model)
         }

+ 6 - 0
QuickSearchLocation/Classes/Pages/QSLMessage/View/QSLMessageHeaderView.swift

@@ -101,6 +101,9 @@ class QSLMessageHeaderView: UIView {
     
     @objc func refuseBtnAction() {
         
+        ///拒绝好友申请埋点
+        gravityInstance?.track(QSLGravityConst.friend_reject_request, properties: ["id": 04006])
+        
         if let model = self.model {
             delegate?.refuseBtnAction(model: model)
         }
@@ -108,6 +111,9 @@ class QSLMessageHeaderView: UIView {
     
     @objc func agreeBtnAction() {
         
+        ///拒绝好友申请埋点
+        gravityInstance?.track(QSLGravityConst.friend_agree_request, properties: ["id": 04005])
+        
         if let model = self.model {
             delegate?.accpetBtnAction(model: model)
         }

+ 29 - 0
QuickSearchLocation/Classes/Pages/QSLRoad/Controller/QSLRoadController.swift

@@ -293,6 +293,28 @@ extension QSLRoadController:MAMapViewDelegate, AMapLocationManagerDelegate {
        return nil
     }
     
+    func mapView(_ mapView: MAMapView!, didSingleTappedAt coordinate: CLLocationCoordinate2D) {
+        
+        ///点击轨迹
+        if QSLBaseManager.shared.isVip() {
+            gravityInstance?.track(QSLGravityConst.vip_location_click_Track, properties: ["id": 03006])
+        } else {
+            gravityInstance?.track(QSLGravityConst.location_click_Track, properties: ["id": 03007])
+        }
+          /*// 直接获取被点击的轨迹线(支持多段线同时选中)
+          let hittedPolylines = mapView.getHittedPolylines(with: coordinate, traverseAll: false)
+          
+          if let polyline = hittedPolylines?.first as? MAPolyline {
+              print("点击了轨迹线,包含 \(polyline.pointCount) 个点")
+              ///点击轨迹
+              if QSLBaseManager.shared.isVip() {
+                  gravityInstance?.track(QSLGravityConst.vip_location_click_Track, properties: ["id": 03006])
+              } else {
+                  gravityInstance?.track(QSLGravityConst.location_click_Track, properties: ["id": 03007])
+              }
+          }*/
+      }
+    
 //    // 查询个人位置
 //    func searchMineLocation() {
 //        
@@ -520,6 +542,13 @@ extension QSLRoadController: QSLRoadMainViewDelegate {
     func searchClickAction() {
         
         gravityInstance?.track(QSLGravityConst.road_search)
+        if QSLBaseManager.shared.isVip() {
+            //点击搜索埋点
+            gravityInstance?.track(QSLGravityConst.vip_location_click_queryTrack, properties: ["id": 03008])
+        } else {
+            //点击搜索埋点
+            gravityInstance?.track(QSLGravityConst.location_click_queryTrack, properties: ["id": 03009])
+        }
         self.requestRoad()
     }
     

+ 119 - 6
QuickSearchLocation/Classes/Pages/QSLVip/Controller/QSLVipController.swift

@@ -14,11 +14,15 @@ enum QSLVipJumpType: Int {
     case add         // 添加好友
     case friendRoad  // 好友列表查看轨迹
     case contact     // 添加紧急联系人
-    case mine        // 
+    case mine        //
+    case guideComments // 引导评论
 }
 
 class QSLVipController: QSLBaseController {
     
+    // 购买人数
+    static let record_non_member_clicks_to_claim = "RECORD_NON_MEMBER_CLIKS_CLAIM"
+    
     struct UX {
         static let mostCellHeight = 113.0.rpx
         static let collectionRowHeight = 137.0.rpx
@@ -326,6 +330,69 @@ class QSLVipController: QSLBaseController {
         return label
     }()
     
+    lazy var bottomContentView: UIView = {
+        let view = UIView()
+        return view
+    }()
+    
+    lazy var bottomTopView: UIView = {
+        let view = UIView()
+        view.isHidden = true
+        view.backgroundColor = .hexStringColor(hexString: "#FFFED8")
+        view.addRadius(radius: 30.rpx)
+        return view
+    }()
+    
+    
+    lazy var bottomTopLabel: UILabel = {
+        let label = UILabel()
+        label.text = ""
+        return label
+    }()
+    
+    func bottomTopLabelInfo(_ goodInfo : QSLGoodModel) {
+        let darkGrayAttributes: [NSAttributedString.Key: Any] = [
+            .foregroundColor: UIColor.hexStringColor(hexString: "#404040"),
+            .font: UIFont.systemFont(ofSize: 11),
+            .paragraphStyle: {
+                let paragraphStyle = NSMutableParagraphStyle()
+                paragraphStyle.alignment = .center
+                return paragraphStyle
+            }(),
+            .kern: -1
+        ]
+
+        // 创建绿色文本样式
+        let greenAttributes: [NSAttributedString.Key: Any] = [
+            .foregroundColor: UIColor.hexStringColor(hexString: "#EE6C1C"),
+            .font:  UIFont.systemFont(ofSize: 15, weight: .black),
+            .paragraphStyle: {
+                let paragraphStyle = NSMutableParagraphStyle()
+                paragraphStyle.alignment = .center
+                return paragraphStyle
+            }(),
+            .kern: -1
+        ]
+        
+        let textArray = goodInfo.text.components(separatedBy: goodInfo.keys.key)
+        if textArray.count > 0 && goodInfo.text.count > 0{
+            bottomTopView.isHidden = false
+            let inputtr = NSMutableAttributedString()
+            let titleOneAttr = NSAttributedString(string: textArray.first ?? "", attributes: darkGrayAttributes)
+            let titleTwoAttr = NSAttributedString(string: " \(goodInfo.keys.value) ", attributes: greenAttributes)
+            inputtr.append(titleOneAttr)
+            inputtr.append(titleTwoAttr)
+            if textArray.count > 1 {
+                let titleThreeAttr = NSAttributedString(string: textArray[1], attributes: darkGrayAttributes)
+                inputtr.append(titleThreeAttr)
+            }
+            bottomTopLabel.attributedText = inputtr
+        } else {
+            bottomTopView.isHidden = true
+        }
+
+    }
+    
     lazy var bottomView: UIView = {
        
         let view = UIView()
@@ -406,6 +473,8 @@ class QSLVipController: QSLBaseController {
                 gravityInstance?.track(QSLGravityConst.vip_show, properties: ["id": 1004])
             case .mine:
                 gravityInstance?.track(QSLGravityConst.vip_show, properties: ["id": 1006])
+            case .guideComments:
+                print("")
             }
         }
     }
@@ -529,11 +598,17 @@ extension QSLVipController {
         
         if goodList.count > 0, let selectGood = self.selectGood {
             QSLLoading.show()
-            QSLVipManager.shared.startPay(goods: selectGood) { status, outTradeNo in
+            QSLVipManager.shared.startPay(goods: selectGood) { [self] status, outTradeNo in
                 QSLVipManager.shared.isPaying = false
                 if status == .success {
                     QSLLoading.success(text: "支付成功")
                     
+                    //支付成功埋点
+                    gravityInstance?.track(QSLGravityConst.vip_submit_success, properties: ["id": 01001])
+                    
+                    //弹出是否好评的弹窗
+                    QSLGuideusersToCommentManager.commentShare.manageWhetherTriggerPopUpWindow(QSLGuideusersToCommentType.member)
+                    
                     // 引力传递支付事件
                     if let selectGood = self.selectGood {
                         gravityInstance?.trackPayEvent(withAmount: Int32(selectGood.amount), withPayType: "CNY", withOrderId: outTradeNo, withPayReason: selectGood.name, withPayMethod: "apple")
@@ -557,6 +632,8 @@ extension QSLVipController {
                             gravityInstance?.track(QSLGravityConst.vip_success_page, properties: ["id": 1004])
                         case .mine:
                             gravityInstance?.track(QSLGravityConst.vip_success_page, properties: ["id": 1006])
+                        case .guideComments:
+                            print("")
                         }
                     }
 
@@ -643,8 +720,18 @@ extension QSLVipController {
     
     // 请求商品列表
     func requestItemList() {
+        // 定义并赋值 itemListDict(根据条件变化)
+        var itemListDict: [String: Any] = ["itemListType": 2]
+        if UserDefaults.standard.string(forKey: QSLVipController.record_non_member_clicks_to_claim) == nil && self.type == .guideComments {
+            itemListDict = ["itemListType": 2, "showExtraText": true]
+            // 记录非会员点击领取
+            UserDefaults.standard.set("YES", forKey: QSLVipController.record_non_member_clicks_to_claim)
+            UserDefaults.standard.synchronize()
+        }
         
-        QSLNetwork().request(.vipItemList(dict: ["itemListType": 2])) { response in
+        // 网络请求时使用 itemListDict 作为参数(关键修复)
+        QSLNetwork().request(.vipItemList(dict: itemListDict)) { response in
+            // 后续逻辑不变...
             let list = response.mapArray(QSLGoodModel.self, modelKey: "data>list")
             self.goodList = list
             
@@ -796,7 +883,7 @@ extension QSLVipController {
             if model.permanent {
                 
                 self.vipTimeLabel.text("您已是尊贵的永久会员")
-                self.bottomView.isHidden = true
+                self.bottomContentView.isHidden = true
             } else {
                 
                 let level = model.memberLevelString()
@@ -828,6 +915,9 @@ extension QSLVipController {
         self.priceLabel.text(priceText)
 //        self.goodTypeLabel.text("/ \(self.selectGood?.name ?? "")")
         self.goodOriginalPriceLabel.text("原价\(originalPriceText)")
+        
+        ///底部内容
+        bottomTopLabelInfo(self.selectGood ?? QSLGoodModel())
     }
     
     func initializeView() {
@@ -1013,11 +1103,34 @@ extension QSLVipController {
             make.bottom.equalTo(mainView)
         }
         
-        self.view.addSubview(bottomView)
-        bottomView.snp.makeConstraints { make in
+        self.view.addSubview(bottomContentView)
+        bottomContentView.snp.makeConstraints { make in
             make.left.equalTo(12.rpx)
             make.right.equalTo(-12.rpx)
             make.bottom.equalTo(-QSLConst.qsl_kTabbarBottom)
+            make.height.equalTo(72.rpx)
+        }
+        
+        bottomContentView.addSubview(bottomTopView)
+        bottomTopView.snp.makeConstraints { make in
+            make.left.equalToSuperview()
+            make.right.equalToSuperview()
+            make.top.equalToSuperview()
+            make.height.equalTo(60.rpx)
+        }
+        
+        bottomTopView.addSubview(bottomTopLabel)
+        bottomTopLabel.snp.makeConstraints { make in
+            make.left.equalToSuperview().offset(22)
+            make.top.equalToSuperview()
+            make.height.equalTo(21.rpx)
+        }
+        
+        bottomContentView.addSubview(bottomView)
+        bottomView.snp.makeConstraints { make in
+            make.left.equalToSuperview()
+            make.right.equalToSuperview()
+            make.bottom.equalToSuperview()
             make.height.equalTo(50.rpx)
         }
         

+ 68 - 0
QuickSearchLocation/Classes/Pages/QSLVip/QSLInAppReviewmanager.swift

@@ -0,0 +1,68 @@
+//
+//  QSLInAppReviewmanager.swift
+//  QuickSearchLocation
+//
+//  Created by Destiny on 2025/7/30.
+//
+
+import StoreKit
+
+class QSLInAppReviewmanager {
+    // 记录应用启动次数
+    static let launchCountKey = "AppLaunchCount"
+    
+    // 检查并请求评论
+    static func requestReviewIfAppropriate() {
+        // 获取应用启动次数
+        let defaults = UserDefaults.standard
+        var launchCount = defaults.integer(forKey: launchCountKey)
+        launchCount += 1
+        defaults.set(launchCount, forKey: launchCountKey)
+        
+        // 在适当的时机请求评论(例如第5次、第20次启动等)
+        if launchCount == 5 || launchCount == 20 || launchCount == 50 {
+            requestReview()
+        }
+    }
+    
+    // 直接请求评论(需要满足App Store的条件才会显示)
+    static func requestReview() {
+        if #available(iOS 14.0, *) {
+            // 获取当前窗口场景
+            if let windowScene = UIApplication.shared.connectedScenes
+                .first(where: { $0.activationState == .foregroundActive }) as? UIWindowScene {
+                SKStoreReviewController.requestReview(in: windowScene)
+            }
+        } else {
+            // iOS 14以下版本
+            SKStoreReviewController.requestReview()
+        }
+    }
+    
+    // 引导用户到App Store评论页面(备用方案)
+    static func openAppStoreReviewPage() {
+        guard let appId = Bundle.main.object(forInfoDictionaryKey: "CFBundleIdentifier") as? String else { return }
+        let urlString = "itms-apps://itunes.apple.com/app/id\(appId)?action=write-review"
+        
+        if let url = URL(string: urlString), UIApplication.shared.canOpenURL(url) {
+            UIApplication.shared.open(url, options: [:], completionHandler: nil)
+        }
+    }
+}
+/*
+// 使用示例
+// 在应用启动时调用(通常在AppDelegate或SceneDelegate中)
+func applicationDidBecomeActive(_ application: UIApplication) {
+    InAppReviewManager.requestReviewIfAppropriate()
+}
+
+// 或者在用户完成关键操作后调用
+func userCompletedSignificantAction() {
+    InAppReviewManager.requestReview()
+}
+
+// 作为备用方案,在用户拒绝原生弹窗后引导到App Store
+func showAppStoreReviewPage() {
+    InAppReviewManager.openAppStoreReviewPage()
+}
+*/

+ 340 - 0
QuickSearchLocation/Classes/Pages/QSLVip/View/QSLVipAlertView.swift

@@ -0,0 +1,340 @@
+//
+//  QSLVipAlertView.swift
+//  QuickSearchLocation
+//
+//  Created by Destiny on 2025/7/28.
+//
+
+import UIKit
+
+class QSLVipAlertView: UIView {
+    
+    
+    lazy var contentView: UIView = {
+        
+        let contentViewW = QSLConst.qsl_kScreenW - 60.rpx
+        let contentViewH =  152.0.rpx
+        let contentView = UIView(frame: CGRect(x: 0, y: 0, width: contentViewW, height: contentViewH))
+        contentView.backgroundColor = .white
+        contentView.addRadius(radius: 8.rpx)
+        contentView.addBorder(borderWidth: 3.rpx, borderColor:  .hexStringColor(hexString: "#FFFFFF"))
+        return contentView
+    }()
+    
+    lazy var centerImage : UIImageView = {
+        let centerImage = UIImageView()
+        centerImage.contentMode = .scaleAspectFit
+        centerImage.image = UIImage(named: "vip_comment_give_thumb")
+        return centerImage
+    }()
+    
+    //渐变色
+    lazy var headerColorView: UIView = {
+        let headerColorViewW = QSLConst.qsl_kScreenW - 60.rpx
+        let headerColorView = UIView(frame: CGRect(x: 0, y: 0, width: headerColorViewW, height: 100))
+        headerColorView.layer.masksToBounds = true
+
+        // 创建渐变图层
+        let gradientLayer = CAGradientLayer()
+        gradientLayer.frame = headerColorView.bounds
+
+        // 设置渐变颜色 (#9EFFEC 到白色)
+        gradientLayer.colors = [
+            UIColor(red: 0.62, green: 1.0, blue: 0.93, alpha: 1.0).cgColor, // #9EFFEC
+            UIColor.white.cgColor
+        ]
+
+        // 设置渐变方向 (180deg 表示从上到下)
+        gradientLayer.startPoint = CGPoint(x: 0.5, y: 0.0)  // 顶部中点
+        gradientLayer.endPoint = CGPoint(x: 0.5, y: 1.0)    // 底部中点
+
+        // 添加渐变图层到视图
+        headerColorView.layer.insertSublayer(gradientLayer, at: 0)
+        return headerColorView
+
+    }()
+    
+    lazy var titleLabel: UILabel = {
+      
+        let label = UILabel()
+        label.text("给我们一个好评呗~")
+        label.mediumFont(20)
+        label.textColor = QSLColor.textColor_333
+        return label
+    }()
+    
+    ///中间描述区域
+    lazy var middleView : UIView = {
+        let middleView = UIView()
+        middleView.backgroundColor = .white
+        return middleView
+    }()
+    
+    lazy var leftMiddleView : UIView = {
+        let leftMiddleView = UIView(frame: CGRectMake(0, 0, 14.rpx, 1.rpx))
+        leftMiddleView.gradientBackgroundColor(color1: .hexStringColor(hexString: "#AAAAAA",alpha: 0.0), color2: .hexStringColor(hexString: "#AAAAAA"), width: 14.rpx, height: 1.rpx, direction: .horizontal)
+        return leftMiddleView
+    }()
+    
+    lazy var rithMiddleView : UIView = {
+        let rithMiddleView = UIView(frame: CGRectMake(0, 0, 14, 1))
+        rithMiddleView.gradientBackgroundColor(color1: .hexStringColor(hexString: "#AAAAAA"), color2: .hexStringColor(hexString: "#AAAAAA",alpha: 0.0), width: 14.rpx, height: 1.rpx, direction: .horizontal)
+        return rithMiddleView
+    }()
+    
+    lazy var contentLabel: UILabel = {
+        let label = UILabel()
+        label.numberOfLines = 0
+        label.textAlignment = .center
+        label.text("登录之后才可以发送好友申请")
+        label.font(12)
+        label.textColor = .hexStringColor(hexString: "#00000099" ,alpha: 0.4)
+        label.changeLineSpace(space: 4)
+        return label
+    }()
+    
+    lazy var oneButton: UIButton = {
+      
+        let btn = UIButton()
+        btn.addRadius(radius: 20.rpx)
+        btn.title("去登录")
+        btn.textColor(.white)
+        btn.mediumFont(16)
+        btn.gradientBackgroundColor(color1: .hexStringColor(hexString: "#15CBA1"), color2: .hexStringColor(hexString: "#1FE0BA"), width: 150.rpx, height: 40.rpx, direction: .horizontal)
+        btn.addTarget(self, action: #selector(oneBtnAction), for: .touchUpInside)
+        return btn
+    }()
+    
+    lazy var firstButton: UIButton = {
+        
+        let btn = UIButton()
+        btn.isHidden = true
+        btn.backgroundColor = .hexStringColor(hexString: "#F8F8F8")
+        btn.addRadius(radius: 20.rpx)
+        btn.title("取消")
+        btn.textColor(.hexStringColor(hexString: "#A7A7A7"))
+        btn.mediumFont(16)
+        btn.addTarget(self, action: #selector(firstBtnAction), for: .touchUpInside)
+        return btn
+    }()
+    
+    lazy var secondButton: UIButton = {
+        
+        let btn = UIButton()
+        btn.isHidden = true
+        btn.addRadius(radius: 20.rpx)
+        btn.title("确认")
+        btn.textColor(.white)
+        btn.mediumFont(16)
+        btn.gradientBackgroundColor(color1: .hexStringColor(hexString: "#15CBA1"), color2: .hexStringColor(hexString: "#1FE0BA"), width: 118.rpx, height: 40.rpx, direction: .horizontal)
+        btn.addTarget(self, action: #selector(secondBtnAction), for: .touchUpInside)
+        return btn
+    }()
+    
+    lazy var closeButton: UIButton = {
+       
+        let btn = UIButton()
+        btn.setBackgroundImage(UIImage(named: "public_btn_close_AAA"), for: .normal)
+        btn.addTarget(self, action: #selector(closeBtnAction), for: .touchUpInside)
+        return btn
+    }()
+    
+    var oneBtnClosure: (() -> ())?
+    
+    var firstBtnClosure: (() -> ())?
+    
+    var secondBtnClosure: (() -> ())?
+    
+    var closeBtnClosure: (() -> ())?
+    
+    
+    class func alert(view: UIView,
+                     title: String,
+                     titleAttring: NSAttributedString,
+                     content: String,
+                     isOneBtn: Bool = false,
+                     oneBtnText: String = "去登录",
+                     oneBtnClosure: @escaping () -> () = {},
+                     firstBtnClosure: @escaping () -> () = {},
+                     secondBtnClosure: @escaping () -> () = {},
+                     closeBtnClosure: @escaping () -> () = {}) {
+        
+        let window = QSLVipAlertView(frame: CGRect(x: 0, y: 0, width: QSLConst.qsl_kScreenW, height: QSLConst.qsl_kScreenH))
+        if title.count > 0 {
+            window.titleLabel.text = title
+        } else {
+            window.titleLabel.attributedText = titleAttring
+        }
+        window.contentLabel.text = content
+        window.contentLabel.changeLineSpace(space: 4)
+        window.oneButton.title(oneBtnText)
+        window.oneButton.isHidden = !isOneBtn
+        window.firstButton.isHidden = isOneBtn
+        window.secondButton.isHidden = isOneBtn
+        window.oneBtnClosure = oneBtnClosure
+        window.firstBtnClosure = firstBtnClosure
+        window.secondBtnClosure = secondBtnClosure
+        window.closeBtnClosure = closeBtnClosure
+        
+        let contentHeight = content.heightAccording(width: QSLConst.qsl_kScreenW - 108.rpx, font: UIFont.textF(15), lineSpacing: 4)
+        window.contentView.snp.remakeConstraints { make in
+            make.size.equalTo(CGSize(width: QSLConst.qsl_kScreenW - 60.rpx, height: 65.rpx + contentHeight + 129.rpx))
+            make.center.equalToSuperview()
+        }
+        view.addSubview(window)
+        
+        
+        UIView.animate(withDuration: 0.4, delay: 0, usingSpringWithDamping: 0.95, initialSpringVelocity: 0.05) {
+            window.backgroundColor = .hexStringColor(hexString: "#000000", alpha: 0.7)
+            window.contentView.isHidden = false
+        }
+    }
+    
+    override init(frame: CGRect) {
+        super.init(frame: frame)
+        
+        initView()
+    }
+    
+    required init?(coder: NSCoder) {
+        fatalError("init(coder:) has not been implemented")
+    }
+    
+    
+    // 单按钮点击事件
+    @objc func oneBtnAction() {
+        if let oneBtnClosure = self.oneBtnClosure {
+            oneBtnClosure()
+        }
+        removeView()
+    }
+    
+    // 取消按钮点击事件
+    @objc func firstBtnAction() {
+        if let firstBtnClosure = self.firstBtnClosure {
+            firstBtnClosure()
+        }
+        removeView()
+    }
+    
+    // 确认按钮点击事件
+    @objc func secondBtnAction() {
+        if let secondBtnClosure = self.secondBtnClosure {
+            secondBtnClosure()
+        }
+        removeView()
+    }
+    
+    // 关闭按钮点击事件
+    @objc func closeBtnAction() {
+        if let closeBtnClosure = self.closeBtnClosure {
+            closeBtnClosure()
+        }
+        removeView()
+    }
+    
+    // 移除
+    @objc func removeView() {
+        
+        UIView.animate(withDuration: 0.4, delay: 0, usingSpringWithDamping: 0.95, initialSpringVelocity: 0.05) { [weak self] in
+            self?.backgroundColor = UIColor.init(white: 0, alpha: 0)
+            self?.contentView.isHidden = true
+        } completion: { [weak self] finished in
+            self?.removeFromSuperview()
+        }
+    }
+}
+
+extension QSLVipAlertView {
+    
+    func initView() {
+        
+        addSubview(contentView)
+        contentView.snp.makeConstraints { make in
+            make.size.equalTo(CGSize(width: QSLConst.qsl_kScreenW - 60.rpx, height: 152.0.rpx))
+            make.center.equalToSuperview()
+        }
+        
+        addSubview(centerImage)
+        centerImage.snp.makeConstraints { make in
+            make.centerX.equalToSuperview()
+            make.top.equalTo(contentView.snp.top).offset(-40.rpx)
+            make.size.equalTo(CGSizeMake(164.6.rpx, 114.rpx))
+        }
+        
+        
+        contentView.addSubview(headerColorView)
+        headerColorView.snp.makeConstraints { make in
+            make.top.equalToSuperview()
+            make.left.equalToSuperview()
+            make.right.equalToSuperview()
+            make.height.equalTo(100)
+        }
+        
+        contentView.addSubview(titleLabel)
+        titleLabel.snp.makeConstraints { make in
+            make.centerX.equalToSuperview()
+            make.top.equalTo(68.rpx)
+        }
+        
+        //中间区域
+        contentView.addSubview(middleView)
+        middleView.snp.makeConstraints { make in
+            make.top.equalTo(titleLabel.snp.bottom).offset(16.5.rpx)
+            make.left.equalTo(0)
+            make.right.equalTo(0)
+            make.height.equalTo(21.rpx)
+        }
+        
+        middleView.addSubview(contentLabel)
+        contentLabel.snp.makeConstraints { make in
+
+            make.center.equalToSuperview()
+            make.height.equalTo(21.rpx)
+        }
+        
+        middleView.addSubview(leftMiddleView)
+        leftMiddleView.snp.makeConstraints { make in
+            make.right.equalTo(contentLabel.snp.left).offset(-6.rpx)
+            make.centerY.equalToSuperview()
+            make.size.equalTo(CGSizeMake(14.rpx, 1.rpx))
+        }
+        
+        middleView.addSubview(rithMiddleView)
+        rithMiddleView.snp.makeConstraints { make in
+            make.left.equalTo(contentLabel.snp.right).offset(6.rpx)
+            make.centerY.equalToSuperview()
+            make.size.equalTo(CGSizeMake(14.rpx, 1.rpx))
+        }
+        
+        contentView.addSubview(oneButton)
+        oneButton.snp.makeConstraints { make in
+            make.size.equalTo(CGSize(width: 150.rpx, height: 40.rpx))
+            make.centerX.equalToSuperview()
+            make.bottom.equalTo(-24.rpx)
+        }
+        
+        contentView.addSubview(firstButton)
+        firstButton.snp.makeConstraints { make in
+            make.size.equalTo(CGSize(width: 118.rpx, height: 40.rpx))
+            make.left.equalTo(24.rpx)
+            make.bottom.equalTo(-24.rpx)
+        }
+        
+        contentView.addSubview(secondButton)
+        secondButton.snp.makeConstraints { make in
+            make.size.equalTo(CGSize(width: 118.rpx, height: 40.rpx))
+            make.right.equalTo(-24.rpx)
+            make.bottom.equalTo(-24.rpx)
+        }
+        
+        contentView.addSubview(closeButton)
+        closeButton.snp.makeConstraints { make in
+            make.size.equalTo(CGSize(width: 24.rpx, height: 24.rpx))
+            make.top.equalTo(12.rpx)
+            make.right.equalTo(-12.rpx)
+        }
+        
+        
+    }
+}

+ 325 - 0
QuickSearchLocation/Classes/Pages/QSLVip/View/QSLVipResultsAlertView.swift

@@ -0,0 +1,325 @@
+//
+//  QSLVipResultsAlertView.swift
+//  QuickSearchLocation
+//
+//  Created by Destiny on 2025/7/29.
+//
+
+import UIKit
+
+class QSLVipResultsAlertView: UIView {
+        
+    lazy var contentView: UIView = {
+        
+        let contentViewW = QSLConst.qsl_kScreenW - 60.rpx
+        let contentViewH =  152.0.rpx
+        let contentView = UIView(frame: CGRect(x: 0, y: 0, width: contentViewW, height: contentViewH))
+        contentView.backgroundColor = .white
+        contentView.addRadius(radius: 8.rpx)
+        contentView.addBorder(borderWidth: 3.rpx, borderColor:  .hexStringColor(hexString: "#FFFFFF"))
+        return contentView
+    }()
+    
+    
+    //渐变色
+    lazy var headerColorView: UIView = {
+        let headerColorViewW = QSLConst.qsl_kScreenW - 60.rpx
+        let headerColorView = UIView(frame: CGRect(x: 0, y: 0, width: headerColorViewW, height: 100))
+        headerColorView.layer.masksToBounds = true
+
+        // 创建渐变图层
+        let gradientLayer = CAGradientLayer()
+        gradientLayer.frame = headerColorView.bounds
+
+        // 设置渐变颜色 (#9EFFEC 到白色)
+        gradientLayer.colors = [
+            UIColor(red: 0.62, green: 1.0, blue: 0.93, alpha: 1.0).cgColor, // #9EFFEC
+            UIColor.white.cgColor
+        ]
+
+        // 设置渐变方向 (180deg 表示从上到下)
+        gradientLayer.startPoint = CGPoint(x: 0.5, y: 0.0)  // 顶部中点
+        gradientLayer.endPoint = CGPoint(x: 0.5, y: 1.0)    // 底部中点
+
+        // 添加渐变图层到视图
+        headerColorView.layer.insertSublayer(gradientLayer, at: 0)
+        return headerColorView
+
+    }()
+    
+    lazy var titleLabel: UILabel = {
+      
+        let label = UILabel()
+        label.text("给我们一个好评呗~")
+        label.mediumFont(20)
+        label.textColor = QSLColor.textColor_333
+        return label
+    }()
+    
+    ///中间描述区域
+    lazy var middleView : UIView = {
+        let middleView = UIView()
+        middleView.backgroundColor = .clear
+        return middleView
+    }()
+    
+    lazy var leftMiddleView : UIView = {
+        let leftMiddleView = UIView(frame: CGRectMake(0, 0, 14.rpx, 1.rpx))
+        leftMiddleView.gradientBackgroundColor(color1: .hexStringColor(hexString: "#AAAAAA",alpha: 0.0), color2: .hexStringColor(hexString: "#AAAAAA"), width: 14.rpx, height: 1.rpx, direction: .horizontal)
+        return leftMiddleView
+    }()
+    
+    lazy var rithMiddleView : UIView = {
+        let rithMiddleView = UIView(frame: CGRectMake(0, 0, 14, 1))
+        rithMiddleView.gradientBackgroundColor(color1: .hexStringColor(hexString: "#AAAAAA"), color2: .hexStringColor(hexString: "#AAAAAA",alpha: 0.0), width: 14.rpx, height: 1.rpx, direction: .horizontal)
+        return rithMiddleView
+    }()
+    
+    lazy var contentLabel: UILabel = {
+        let label = UILabel()
+        label.numberOfLines = 0
+        label.textAlignment = .center
+        label.text("登录之后才可以发送好友申请")
+        label.font(12)
+        label.textColor = .hexStringColor(hexString: "#00000099" ,alpha: 0.4)
+        label.changeLineSpace(space: 4)
+        return label
+    }()
+    
+    lazy var oneButton: UIButton = {
+      
+        let btn = UIButton()
+        btn.addRadius(radius: 20.rpx)
+        btn.title("去登录")
+        btn.textColor(.white)
+        btn.mediumFont(16)
+        btn.gradientBackgroundColor(color1: .hexStringColor(hexString: "#15CBA1"), color2: .hexStringColor(hexString: "#1FE0BA"), width: 150.rpx, height: 40.rpx, direction: .horizontal)
+        btn.addTarget(self, action: #selector(oneBtnAction), for: .touchUpInside)
+        return btn
+    }()
+    
+    lazy var firstButton: UIButton = {
+        
+        let btn = UIButton()
+        btn.isHidden = true
+        btn.backgroundColor = .hexStringColor(hexString: "#F8F8F8")
+        btn.addRadius(radius: 20.rpx)
+        btn.title("取消")
+        btn.textColor(.hexStringColor(hexString: "#A7A7A7"))
+        btn.mediumFont(16)
+        btn.addTarget(self, action: #selector(firstBtnAction), for: .touchUpInside)
+        return btn
+    }()
+    
+    lazy var secondButton: UIButton = {
+        
+        let btn = UIButton()
+        btn.isHidden = true
+        btn.addRadius(radius: 20.rpx)
+        btn.title("确认")
+        btn.textColor(.white)
+        btn.mediumFont(16)
+        btn.gradientBackgroundColor(color1: .hexStringColor(hexString: "#15CBA1"), color2: .hexStringColor(hexString: "#1FE0BA"), width: 118.rpx, height: 40.rpx, direction: .horizontal)
+        btn.addTarget(self, action: #selector(secondBtnAction), for: .touchUpInside)
+        return btn
+    }()
+    
+    lazy var closeButton: UIButton = {
+       
+        let btn = UIButton()
+        btn.setBackgroundImage(UIImage(named: "public_btn_close_AAA"), for: .normal)
+        btn.addTarget(self, action: #selector(closeBtnAction), for: .touchUpInside)
+        return btn
+    }()
+    
+    var oneBtnClosure: (() -> ())?
+    
+    var firstBtnClosure: (() -> ())?
+    
+    var secondBtnClosure: (() -> ())?
+    
+    var closeBtnClosure: (() -> ())?
+    
+    
+    class func alert(view: UIView,
+                     title: String,
+                     titleAttring: NSAttributedString,
+                     content: String,
+                     isOneBtn: Bool = false,
+                     oneBtnText: String = "去登录",
+                     oneBtnClosure: @escaping () -> () = {},
+                     firstBtnClosure: @escaping () -> () = {},
+                     secondBtnClosure: @escaping () -> () = {},
+                     closeBtnClosure: @escaping () -> () = {}) {
+        
+        let window = QSLVipResultsAlertView(frame: CGRect(x: 0, y: 0, width: QSLConst.qsl_kScreenW, height: QSLConst.qsl_kScreenH))
+        if title.count > 0 {
+            window.titleLabel.text = title
+        } else {
+            window.titleLabel.attributedText = titleAttring
+        }
+        window.contentLabel.text = content
+        window.contentLabel.changeLineSpace(space: 4)
+        window.oneButton.title(oneBtnText)
+        window.oneButton.isHidden = !isOneBtn
+        window.firstButton.isHidden = isOneBtn
+        window.secondButton.isHidden = isOneBtn
+        window.oneBtnClosure = oneBtnClosure
+        window.firstBtnClosure = firstBtnClosure
+        window.secondBtnClosure = secondBtnClosure
+        window.closeBtnClosure = closeBtnClosure
+        
+        window.contentView.snp.remakeConstraints { make in
+            var windowContentH : CGFloat = 189.rpx
+            make.size.equalTo(CGSize(width: QSLConst.qsl_kScreenW - 60.rpx, height: windowContentH))
+            make.center.equalToSuperview()
+        }
+        view.addSubview(window)
+        
+        UIView.animate(withDuration: 0.4, delay: 0, usingSpringWithDamping: 0.95, initialSpringVelocity: 0.05) {
+            window.backgroundColor = .hexStringColor(hexString: "#000000", alpha: 0.7)
+            window.contentView.isHidden = false
+        }
+    }
+    
+    override init(frame: CGRect) {
+        super.init(frame: frame)
+        
+        initView()
+    }
+    
+    required init?(coder: NSCoder) {
+        fatalError("init(coder:) has not been implemented")
+    }
+    
+    
+    // 单按钮点击事件
+    @objc func oneBtnAction() {
+        if let oneBtnClosure = self.oneBtnClosure {
+            oneBtnClosure()
+        }
+        removeView()
+    }
+    
+    // 取消按钮点击事件
+    @objc func firstBtnAction() {
+        if let firstBtnClosure = self.firstBtnClosure {
+            firstBtnClosure()
+        }
+        removeView()
+    }
+    
+    // 确认按钮点击事件
+    @objc func secondBtnAction() {
+        if let secondBtnClosure = self.secondBtnClosure {
+            secondBtnClosure()
+        }
+        removeView()
+    }
+    
+    // 关闭按钮点击事件
+    @objc func closeBtnAction() {
+        if let closeBtnClosure = self.closeBtnClosure {
+            closeBtnClosure()
+        }
+        removeView()
+    }
+    
+    // 移除
+    @objc func removeView() {
+        
+        UIView.animate(withDuration: 0.4, delay: 0, usingSpringWithDamping: 0.95, initialSpringVelocity: 0.05) { [weak self] in
+            self?.backgroundColor = UIColor.init(white: 0, alpha: 0)
+            self?.contentView.isHidden = true
+        } completion: { [weak self] finished in
+            self?.removeFromSuperview()
+        }
+    }
+}
+
+extension QSLVipResultsAlertView {
+    
+    func initView() {
+        
+        addSubview(contentView)
+        contentView.snp.makeConstraints { make in
+            make.size.equalTo(CGSize(width: QSLConst.qsl_kScreenW - 60.rpx, height: 152.0.rpx))
+            make.center.equalToSuperview()
+        }
+        
+        contentView.addSubview(headerColorView)
+        headerColorView.snp.makeConstraints { make in
+            make.top.equalToSuperview()
+            make.left.equalToSuperview()
+            make.right.equalToSuperview()
+            make.height.equalTo(100)
+        }
+        
+        contentView.addSubview(titleLabel)
+        titleLabel.snp.makeConstraints { make in
+            make.centerX.equalToSuperview()
+            make.top.equalTo(40.rpx)
+        }
+        
+        //中间区域
+        contentView.addSubview(middleView)
+        middleView.snp.makeConstraints { make in
+
+            make.top.equalTo(titleLabel.snp.bottom).offset(9.rpx)
+            make.left.equalTo(0)
+            make.right.equalTo(0)
+            make.height.equalTo(21.rpx)
+        }
+        
+        middleView.addSubview(contentLabel)
+        contentLabel.snp.makeConstraints { make in
+            make.center.equalToSuperview()
+            make.height.equalTo(21.rpx)
+        }
+        
+        middleView.addSubview(leftMiddleView)
+        leftMiddleView.snp.makeConstraints { make in
+            make.right.equalTo(contentLabel.snp.left).offset(-6.rpx)
+            make.centerY.equalToSuperview()
+            make.size.equalTo(CGSizeMake(14.rpx, 1.rpx))
+        }
+        
+        middleView.addSubview(rithMiddleView)
+        rithMiddleView.snp.makeConstraints { make in
+            make.left.equalTo(contentLabel.snp.right).offset(6.rpx)
+            make.centerY.equalToSuperview()
+            make.size.equalTo(CGSizeMake(14.rpx, 1.rpx))
+        }
+        
+        contentView.addSubview(oneButton)
+        oneButton.snp.makeConstraints { make in
+            //make.top.equalTo(contentLabel.snp.bottom).offset(24.5.rpx)
+            make.size.equalTo(CGSize(width: 150.rpx, height: 40.rpx))
+            make.centerX.equalToSuperview()
+            make.bottom.equalTo(-24.rpx)
+        }
+        
+        contentView.addSubview(firstButton)
+        firstButton.snp.makeConstraints { make in
+            make.size.equalTo(CGSize(width: 118.rpx, height: 40.rpx))
+            make.left.equalTo(24.rpx)
+            make.bottom.equalTo(-24.rpx)
+        }
+        
+        contentView.addSubview(secondButton)
+        secondButton.snp.makeConstraints { make in
+            make.size.equalTo(CGSize(width: 118.rpx, height: 40.rpx))
+            make.right.equalTo(-24.rpx)
+            make.bottom.equalTo(-24.rpx)
+        }
+        
+        contentView.addSubview(closeButton)
+        closeButton.snp.makeConstraints { make in
+            make.size.equalTo(CGSize(width: 24.rpx, height: 24.rpx))
+            make.top.equalTo(12.rpx)
+            make.right.equalTo(-12.rpx)
+        }
+        
+        
+    }
+}

+ 422 - 0
QuickSearchLocation/Classes/Pages/QSLVip/View/QSLVipResultsNoMemberAlertView.swift

@@ -0,0 +1,422 @@
+//
+//  QSLVipResultsNoMemberAlertView.swift
+//  QuickSearchLocation
+//
+//  Created by Destiny on 2025/7/29.
+//
+
+import UIKit
+
+class QSLVipResultsNoMemberAlertView: UIView {
+        
+    lazy var contentView: UIView = {
+        
+        let contentViewW = QSLConst.qsl_kScreenW - 60.rpx
+        let contentViewH =  152.0.rpx
+        let contentView = UIView(frame: CGRect(x: 0, y: 0, width: contentViewW, height: contentViewH))
+        contentView.backgroundColor = .white
+        contentView.addRadius(radius: 8.rpx)
+        contentView.addBorder(borderWidth: 3.rpx, borderColor:  .hexStringColor(hexString: "#FFFFFF"))
+        return contentView
+    }()
+    
+    
+    //渐变色
+    lazy var headerColorView: UIView = {
+        let headerColorViewW = QSLConst.qsl_kScreenW - 60.rpx
+        let headerColorView = UIView(frame: CGRect(x: 0, y: 0, width: headerColorViewW, height: 100))
+        headerColorView.layer.masksToBounds = true
+
+        // 创建渐变图层
+        let gradientLayer = CAGradientLayer()
+        gradientLayer.frame = headerColorView.bounds
+
+        // 设置渐变颜色 (#9EFFEC 到白色)
+        gradientLayer.colors = [
+            UIColor(red: 0.62, green: 1.0, blue: 0.93, alpha: 1.0).cgColor, // #9EFFEC
+            UIColor.white.cgColor
+        ]
+
+        // 设置渐变方向 (180deg 表示从上到下)
+        gradientLayer.startPoint = CGPoint(x: 0.5, y: 0.0)  // 顶部中点
+        gradientLayer.endPoint = CGPoint(x: 0.5, y: 1.0)    // 底部中点
+
+        // 添加渐变图层到视图
+        headerColorView.layer.insertSublayer(gradientLayer, at: 0)
+        return headerColorView
+
+    }()
+    
+    lazy var titleLabel: UILabel = {
+      
+        let label = UILabel()
+        label.text("给我们一个好评呗~")
+        label.mediumFont(20)
+        label.textColor = QSLColor.textColor_333
+        return label
+    }()
+    
+        
+    ///广告描述区域
+    lazy var adView : UIView = {
+        let adView = UIView(frame:  CGRectMake(0, 0, 188, 96.2))
+        // 设置阴影
+        layer.masksToBounds = false
+        layer.shadowColor = UIColor(red: 7/255.0, green: 78/255.0, blue: 82/255.0, alpha: 0.16).cgColor
+        layer.shadowOpacity = 1
+        layer.shadowOffset = CGSize(width: 1, height: 6)
+        layer.shadowRadius = 8.rpx
+        layer.shadowPath = UIBezierPath(roundedRect: bounds, cornerRadius: layer.cornerRadius).cgPath
+        layer.shouldRasterize = true
+        layer.rasterizationScale = UIScreen.main.scale
+        adView.addRadius(radius: 8.rpx)
+        adView.addBorder(borderWidth: 1.rpx, borderColor:  .hexStringColor(hexString: "#034249"))
+        return adView
+    }()
+    
+    lazy var adBgImage : UIImageView = {
+        let adBgImage = UIImageView()
+        adBgImage.contentMode = .scaleAspectFill
+        adBgImage.image = UIImage(named: "vip_comment_content_bg")
+        return adBgImage
+    } ()
+    
+    
+    lazy var sunlightImage : UIImageView = {
+        let sunlightImage = UIImageView()
+        sunlightImage.contentMode = .scaleAspectFill
+        sunlightImage.image = UIImage(named: "vip_comment_sunlight")
+        return sunlightImage
+    } ()
+    
+    lazy var adContentLabel: UILabel = {
+        let label = UILabel()
+        label.numberOfLines = 0
+        label.textAlignment = .left
+        label.text("登录之后才可以发送好友申请")
+        label.font(12)
+        label.textColor = .hexStringColor(hexString: "#00000099" ,alpha: 0.4)
+        label.changeLineSpace(space: 4)
+        return label
+    }()
+    
+
+    ///中间描述区域
+    lazy var middleView : UIView = {
+        let middleView = UIView()
+        middleView.backgroundColor = .clear
+        return middleView
+    }()
+    
+    lazy var contentLabel: UILabel = {
+        let label = UILabel()
+        label.numberOfLines = 0
+        label.textAlignment = .center
+        label.text("登录之后才可以发送好友申请")
+        label.font(12)
+        label.textColor = .hexStringColor(hexString: "#00000099" ,alpha: 0.4)
+        label.changeLineSpace(space: 4)
+        return label
+    }()
+    
+    lazy var leftMiddleView : UIView = {
+        let leftMiddleView = UIView(frame: CGRectMake(0, 0, 14.rpx, 1.rpx))
+        leftMiddleView.gradientBackgroundColor(color1: .hexStringColor(hexString: "#AAAAAA",alpha: 0.0), color2: .hexStringColor(hexString: "#AAAAAA"), width: 14.rpx, height: 1.rpx, direction: .horizontal)
+        return leftMiddleView
+    }()
+    
+    lazy var rithMiddleView : UIView = {
+        let rithMiddleView = UIView(frame: CGRectMake(0, 0, 14, 1))
+        rithMiddleView.gradientBackgroundColor(color1: .hexStringColor(hexString: "#AAAAAA"), color2: .hexStringColor(hexString: "#AAAAAA",alpha: 0.0), width: 14.rpx, height: 1.rpx, direction: .horizontal)
+        return rithMiddleView
+    }()
+    
+    //中间广告提示
+    lazy var advertsingPromptView : UIView = {
+        let advertsingPromptView = UIView()
+        return advertsingPromptView
+    }()
+    
+    
+    lazy var oneButton: UIButton = {
+      
+        let btn = UIButton()
+        btn.addRadius(radius: 20.rpx)
+        btn.title("去登录")
+        btn.textColor(.white)
+        btn.mediumFont(16)
+        btn.gradientBackgroundColor(color1: .hexStringColor(hexString: "#15CBA1"), color2: .hexStringColor(hexString: "#1FE0BA"), width: 150.rpx, height: 40.rpx, direction: .horizontal)
+        btn.addTarget(self, action: #selector(oneBtnAction), for: .touchUpInside)
+        return btn
+    }()
+    
+    lazy var firstButton: UIButton = {
+        
+        let btn = UIButton()
+        btn.isHidden = true
+        btn.backgroundColor = .hexStringColor(hexString: "#F8F8F8")
+        btn.addRadius(radius: 20.rpx)
+        btn.title("取消")
+        btn.textColor(.hexStringColor(hexString: "#A7A7A7"))
+        btn.mediumFont(16)
+        btn.addTarget(self, action: #selector(firstBtnAction), for: .touchUpInside)
+        return btn
+    }()
+    
+    lazy var secondButton: UIButton = {
+        
+        let btn = UIButton()
+        btn.isHidden = true
+        btn.addRadius(radius: 20.rpx)
+        btn.title("确认")
+        btn.textColor(.white)
+        btn.mediumFont(16)
+        btn.gradientBackgroundColor(color1: .hexStringColor(hexString: "#15CBA1"), color2: .hexStringColor(hexString: "#1FE0BA"), width: 118.rpx, height: 40.rpx, direction: .horizontal)
+        btn.addTarget(self, action: #selector(secondBtnAction), for: .touchUpInside)
+        return btn
+    }()
+    
+    lazy var closeButton: UIButton = {
+       
+        let btn = UIButton()
+        btn.setBackgroundImage(UIImage(named: "public_btn_close_AAA"), for: .normal)
+        btn.addTarget(self, action: #selector(closeBtnAction), for: .touchUpInside)
+        return btn
+    }()
+    
+    var oneBtnClosure: (() -> ())?
+    
+    var firstBtnClosure: (() -> ())?
+    
+    var secondBtnClosure: (() -> ())?
+    
+    var closeBtnClosure: (() -> ())?
+    
+    
+    class func alert(view: UIView,
+                     title: String,
+                     titleAttring: NSAttributedString,
+                     content: String,
+                     bottomContentAttring: NSAttributedString,
+                     isOneBtn: Bool = false,
+                     oneBtnText: String = "去登录",
+                     oneBtnClosure: @escaping () -> () = {},
+                     firstBtnClosure: @escaping () -> () = {},
+                     secondBtnClosure: @escaping () -> () = {},
+                     closeBtnClosure: @escaping () -> () = {}) {
+        
+        let window = QSLVipResultsNoMemberAlertView(frame: CGRect(x: 0, y: 0, width: QSLConst.qsl_kScreenW, height: QSLConst.qsl_kScreenH))
+        if title.count > 0 {
+            window.titleLabel.text = title
+        } else {
+            window.titleLabel.attributedText = titleAttring
+        }
+        window.contentLabel.text = content
+        window.contentLabel.changeLineSpace(space: 4)
+        window.adContentLabel.attributedText = bottomContentAttring
+        window.oneButton.title(oneBtnText)
+        window.oneButton.isHidden = !isOneBtn
+        window.firstButton.isHidden = isOneBtn
+        window.secondButton.isHidden = isOneBtn
+        window.oneBtnClosure = oneBtnClosure
+        window.firstBtnClosure = firstBtnClosure
+        window.secondBtnClosure = secondBtnClosure
+        window.closeBtnClosure = closeBtnClosure
+        
+        window.contentView.snp.remakeConstraints { make in
+            make.size.equalTo(CGSize(width: QSLConst.qsl_kScreenW - 60.rpx, height: 290.rpx))
+            make.center.equalToSuperview()
+        }
+        view.addSubview(window)
+        
+        UIView.animate(withDuration: 0.4, delay: 0, usingSpringWithDamping: 0.95, initialSpringVelocity: 0.05) {
+            window.backgroundColor = .hexStringColor(hexString: "#000000", alpha: 0.7)
+            window.contentView.isHidden = false
+        }
+    }
+    
+    override init(frame: CGRect) {
+        super.init(frame: frame)
+        
+        initView()
+    }
+    
+    required init?(coder: NSCoder) {
+        fatalError("init(coder:) has not been implemented")
+    }
+    
+    
+    // 单按钮点击事件
+    @objc func oneBtnAction() {
+        if let oneBtnClosure = self.oneBtnClosure {
+            oneBtnClosure()
+        }
+        removeView()
+    }
+    
+    // 取消按钮点击事件
+    @objc func firstBtnAction() {
+        if let firstBtnClosure = self.firstBtnClosure {
+            firstBtnClosure()
+        }
+        removeView()
+    }
+    
+    // 确认按钮点击事件
+    @objc func secondBtnAction() {
+        if let secondBtnClosure = self.secondBtnClosure {
+            secondBtnClosure()
+        }
+        removeView()
+    }
+    
+    // 关闭按钮点击事件
+    @objc func closeBtnAction() {
+        if let closeBtnClosure = self.closeBtnClosure {
+            closeBtnClosure()
+        }
+        removeView()
+    }
+    
+    // 移除
+    @objc func removeView() {
+        
+        UIView.animate(withDuration: 0.4, delay: 0, usingSpringWithDamping: 0.95, initialSpringVelocity: 0.05) { [weak self] in
+            self?.backgroundColor = UIColor.init(white: 0, alpha: 0)
+            self?.contentView.isHidden = true
+        } completion: { [weak self] finished in
+            self?.removeFromSuperview()
+        }
+    }
+}
+
+extension QSLVipResultsNoMemberAlertView {
+    
+    func initView() {
+        
+        addSubview(contentView)
+        contentView.snp.makeConstraints { make in
+            make.size.equalTo(CGSize(width: QSLConst.qsl_kScreenW - 60.rpx, height: 152.0.rpx))
+            make.center.equalToSuperview()
+        }
+        
+        contentView.addSubview(headerColorView)
+        headerColorView.snp.makeConstraints { make in
+            make.top.equalToSuperview()
+            make.left.equalToSuperview()
+            make.right.equalToSuperview()
+            make.height.equalTo(100)
+        }
+        
+        contentView.addSubview(sunlightImage)
+        sunlightImage.snp.makeConstraints { make in
+            make.centerX.equalToSuperview()
+            make.top.equalToSuperview().offset(72.rpx)
+            make.size.equalTo(CGSizeMake(177.rpx, 177.rpx))
+        }
+        
+        contentView.addSubview(titleLabel)
+        titleLabel.snp.makeConstraints { make in
+            make.centerX.equalToSuperview()
+            make.top.equalTo(26.rpx)
+        }
+        
+        //中间区域
+        contentView.addSubview(middleView)
+        middleView.snp.makeConstraints { make in
+            make.top.equalTo(titleLabel.snp.bottom).offset(9.rpx)
+            make.left.equalTo(0)
+            make.right.equalTo(0)
+            make.height.equalTo(21.rpx)
+        }
+        
+        middleView.addSubview(contentLabel)
+        contentLabel.snp.makeConstraints { make in
+            make.center.equalToSuperview()
+            make.height.equalTo(21.rpx)
+        }
+        
+        middleView.addSubview(leftMiddleView)
+        leftMiddleView.snp.makeConstraints { make in
+            make.right.equalTo(contentLabel.snp.left).offset(-6.rpx)
+            make.centerY.equalToSuperview()
+            make.size.equalTo(CGSizeMake(14.rpx, 1.rpx))
+        }
+        
+        middleView.addSubview(rithMiddleView)
+        rithMiddleView.snp.makeConstraints { make in
+            make.left.equalTo(contentLabel.snp.right).offset(6.rpx)
+            make.centerY.equalToSuperview()
+            make.size.equalTo(CGSizeMake(14.rpx, 1.rpx))
+        }
+        
+        ///广告区域
+        contentView.addSubview(adView)
+        adView.snp.makeConstraints { make in
+            make.centerX.equalToSuperview()
+            make.top.equalTo(middleView.snp.bottom).offset(24.5.rpx)
+            make.left.equalToSuperview().offset(44.rpx)
+            make.right.equalToSuperview().offset(-44.rpx)
+            make.height.equalTo(96.2.rpx)
+            //make.size.equalTo(CGSizeMake(188.rpx, 96.2.rpx))
+        }
+        
+        adView.addSubview(adBgImage)
+        adBgImage.snp.makeConstraints { make in
+            make.edges.equalToSuperview()
+        }
+        
+//        adView.addSubview(adTitleLabel)
+//        adTitleLabel.snp.makeConstraints { make in
+//            make.top.equalToSuperview().offset(10.rpx)
+//            make.left.equalToSuperview().offset(12.rpx)
+//            make.right.equalToSuperview()
+//            make.height.equalTo(13.5.rpx)
+//        }
+        
+//        adView.addSubview(adAccessImage)
+//        adAccessImage.snp.makeConstraints { make in
+//            make.right.equalToSuperview()
+//            make.bottom.equalToSuperview()
+//            make.size.equalTo(CGSizeMake(86.5.rpx, 43.8.rpx))
+//        }
+        
+        adView.addSubview(adContentLabel)
+        adContentLabel.snp.makeConstraints { make in
+            make.left.equalToSuperview().offset(10.28.rpx)
+            make.bottom.equalToSuperview().offset(-8.37)
+            //make.right.equalToSuperview()
+        }
+        
+        
+        contentView.addSubview(oneButton)
+        oneButton.snp.makeConstraints { make in
+            //make.top.equalTo(contentLabel.snp.bottom).offset(24.5.rpx)
+            make.size.equalTo(CGSize(width: 150.rpx, height: 40.rpx))
+            make.centerX.equalToSuperview()
+            make.bottom.equalTo(-24.rpx)
+        }
+        
+        contentView.addSubview(firstButton)
+        firstButton.snp.makeConstraints { make in
+            make.size.equalTo(CGSize(width: 118.rpx, height: 40.rpx))
+            make.left.equalTo(24.rpx)
+            make.bottom.equalTo(-24.rpx)
+        }
+        
+        contentView.addSubview(secondButton)
+        secondButton.snp.makeConstraints { make in
+            make.size.equalTo(CGSize(width: 118.rpx, height: 40.rpx))
+            make.right.equalTo(-24.rpx)
+            make.bottom.equalTo(-24.rpx)
+        }
+        
+        contentView.addSubview(closeButton)
+        closeButton.snp.makeConstraints { make in
+            make.size.equalTo(CGSize(width: 24.rpx, height: 24.rpx))
+            make.top.equalTo(12.rpx)
+            make.right.equalTo(-12.rpx)
+        }
+    }
+}
+

+ 9 - 0
QuickSearchLocation/Macro/QSLApi.swift

@@ -181,6 +181,15 @@ extension QSLApi {
     static let vip_subscription_check = "/s/v1/subscription/check"
 }
 
+///好评引导模块
+extension QSLApi {
+    // 是否触发好评引导弹窗
+    static let guide_is_triggered = "/s/v1/guide/is/triggered"
+    
+    // 领取好评引导奖励
+    static let guide_receisve_reward = "/s/v1/guide/receive/reward"
+}
+
 // 定位模块
 extension QSLApi {
     

+ 40 - 0
QuickSearchLocation/Macro/QSLGravityConst.swift

@@ -18,6 +18,12 @@ extension QSLGravityConst {
     
     // 启屏
     static let launch_show = "z8000000"
+    // 启动app
+    static let app_launch = "app_launch"
+    // 退出app
+    static let app_exit = "app_exit"
+    // 累计使用时长
+    static let usage_collect_accumulatedTime = "usage_collect_accumulatedTime"
 }
 
 extension QSLGravityConst {
@@ -44,6 +50,8 @@ extension QSLGravityConst {
     static let tab_message = "z8000116"
     // 我的页面
     static let tab_mine = "z8000117"
+    // 首次进入定位首页
+    static let location_enter_first_homepage = "location_enter_first_homepage"
 }
 
 extension QSLGravityConst {
@@ -86,6 +94,14 @@ extension QSLGravityConst {
     static let road_time_confirm = "z8000803"
     // 查看轨迹页-时间选择-取消
     static let road_time_cancel = "z8000804"
+    // 点击轨迹
+    static let location_click_Track = "location_click_Track"
+    // 会员点击轨迹
+    static let vip_location_click_Track = "vip_location_click_Track"
+    // 点击查询轨迹
+    static let location_click_queryTrack = "location_click_queryTrack"
+    // 会员点击查询轨迹
+    static let vip_location_click_queryTrack = "vip_location_click_queryTrack"
 }
 
 extension QSLGravityConst {
@@ -124,6 +140,20 @@ extension QSLGravityConst {
     static let friend_phoneNum = "z8001312"
     // 好友编辑-查看手机号弹窗-我知道了
     static let friend_phoneNum_click = "z8001313"
+    // 点击添加好友
+    static let friend_click_add = "friend_click_add"
+    // 会员点击添加好友
+    static let vip_friend_click_add = "vip_friend_click_add"
+    // 输入手机号添加成功
+    static let friend_add_success_phone = "vip_friend_add_success_phone"
+    // 输入手机号添加成功
+    static let vip_friend_add_success_phone = "vip_friend_add_success_phone"
+    // 输入手机号添加失败
+    static let vip_friend_add_fail_phone = "vip_friend_add_fail_phone"
+    // 好友同意申请
+    static let friend_agree_request = "friend_agree_request"
+    // 好友拒绝申请
+    static let friend_reject_request = "friend_reject_request"
 }
 
 extension QSLGravityConst {
@@ -170,6 +200,14 @@ extension QSLGravityConst {
     static let contact_resort_all_fail = "z8001619"
     // 紧急联系人短信多条发送-部分错误弹窗
     static let contact_resort_all_fail_alert = "z8001620"
+    // 同意定位权限
+    static let location_allow_permission = "location_allow_permission"
+    // 拒绝定位权限
+    static let location_deny_permission = "location_deny_permission"
+    // 始终允许定位成功
+    static let location_success_always = "location_success_always"
+    // 始终允许定位失败
+    static let location_fail_always = "location_fail_always"
 }
 
 extension QSLGravityConst {
@@ -228,6 +266,8 @@ extension QSLGravityConst {
     static let vip_success_good = "z8002914"
     // 会员办理失败
     static let vip_fail = "z8002906"
+    // 会员支付成功
+    static let vip_submit_success = "vip_submit_success"
 }
 
 extension QSLGravityConst {

+ 22 - 0
QuickSearchLocation/Resources/Assets.xcassets/Vip/vip_comment_content_bg.imageset/Contents.json

@@ -0,0 +1,22 @@
+{
+  "images" : [
+    {
+      "idiom" : "universal",
+      "scale" : "1x"
+    },
+    {
+      "filename" : "vip_comment_content_bg@2x.png",
+      "idiom" : "universal",
+      "scale" : "2x"
+    },
+    {
+      "filename" : "vip_comment_content_bg@3x.png",
+      "idiom" : "universal",
+      "scale" : "3x"
+    }
+  ],
+  "info" : {
+    "author" : "xcode",
+    "version" : 1
+  }
+}

二進制
QuickSearchLocation/Resources/Assets.xcassets/Vip/vip_comment_content_bg.imageset/vip_comment_content_bg@2x.png


二進制
QuickSearchLocation/Resources/Assets.xcassets/Vip/vip_comment_content_bg.imageset/vip_comment_content_bg@3x.png


+ 22 - 0
QuickSearchLocation/Resources/Assets.xcassets/Vip/vip_comment_give_thumb.imageset/Contents.json

@@ -0,0 +1,22 @@
+{
+  "images" : [
+    {
+      "idiom" : "universal",
+      "scale" : "1x"
+    },
+    {
+      "filename" : "vip_comment_give_thumb@2x.png",
+      "idiom" : "universal",
+      "scale" : "2x"
+    },
+    {
+      "filename" : "vip_comment_give_thumb@3x.png",
+      "idiom" : "universal",
+      "scale" : "3x"
+    }
+  ],
+  "info" : {
+    "author" : "xcode",
+    "version" : 1
+  }
+}

二進制
QuickSearchLocation/Resources/Assets.xcassets/Vip/vip_comment_give_thumb.imageset/vip_comment_give_thumb@2x.png


二進制
QuickSearchLocation/Resources/Assets.xcassets/Vip/vip_comment_give_thumb.imageset/vip_comment_give_thumb@3x.png


+ 22 - 0
QuickSearchLocation/Resources/Assets.xcassets/Vip/vip_comment_sunlight.imageset/Contents.json

@@ -0,0 +1,22 @@
+{
+  "images" : [
+    {
+      "idiom" : "universal",
+      "scale" : "1x"
+    },
+    {
+      "filename" : "vip_comment_sunlight@2x.png",
+      "idiom" : "universal",
+      "scale" : "2x"
+    },
+    {
+      "filename" : "vip_comment_sunlight@3x.png",
+      "idiom" : "universal",
+      "scale" : "3x"
+    }
+  ],
+  "info" : {
+    "author" : "xcode",
+    "version" : 1
+  }
+}

二進制
QuickSearchLocation/Resources/Assets.xcassets/Vip/vip_comment_sunlight.imageset/vip_comment_sunlight@2x.png


二進制
QuickSearchLocation/Resources/Assets.xcassets/Vip/vip_comment_sunlight.imageset/vip_comment_sunlight@3x.png