Browse Source

保存文件,区分机构和平台学生

Steven 1 month ago
parent
commit
75f3a83ebd
35 changed files with 908 additions and 91 deletions
  1. 21 1
      KulexiuForStudent/KulexiuForStudent.xcodeproj/project.pbxproj
  2. 1 1
      KulexiuForStudent/KulexiuForStudent.xcodeproj/xcshareddata/xcschemes/KulexiuForStudent.xcscheme
  3. 22 0
      KulexiuForStudent/KulexiuForStudent/Assets.xcassets/download_topLayer.imageset/Contents.json
  4. BIN
      KulexiuForStudent/KulexiuForStudent/Assets.xcassets/download_topLayer.imageset/download_topLayer@2x.png
  5. BIN
      KulexiuForStudent/KulexiuForStudent/Assets.xcassets/download_topLayer.imageset/download_topLayer@3x.png
  6. 236 66
      KulexiuForStudent/KulexiuForStudent/Common/Base/WebView/KSBaseWKWebViewController.m
  7. 25 0
      KulexiuForStudent/KulexiuForStudent/Common/Base/WebView/KSPlatformDownloadAlert.h
  8. 94 0
      KulexiuForStudent/KulexiuForStudent/Common/Base/WebView/KSPlatformDownloadAlert.m
  9. 178 0
      KulexiuForStudent/KulexiuForStudent/Common/Base/WebView/KSPlatformDownloadAlert.xib
  10. 27 0
      KulexiuForStudent/KulexiuForStudent/Common/Base/WebView/KSSourceDownloadAlert.h
  11. 94 0
      KulexiuForStudent/KulexiuForStudent/Common/Base/WebView/KSSourceDownloadAlert.m
  12. 187 0
      KulexiuForStudent/KulexiuForStudent/Common/Base/WebView/KSSourceDownloadAlert.xib
  13. 1 1
      KulexiuForStudent/Pods/Pods.xcodeproj/xcuserdata/wangzhi.xcuserdatad/xcschemes/AFNetworking.xcscheme
  14. 1 1
      KulexiuForStudent/Pods/Pods.xcodeproj/xcuserdata/wangzhi.xcuserdatad/xcschemes/Bugly.xcscheme
  15. 1 1
      KulexiuForStudent/Pods/Pods.xcodeproj/xcuserdata/wangzhi.xcuserdatad/xcschemes/CHIPageControl.xcscheme
  16. 1 1
      KulexiuForStudent/Pods/Pods.xcodeproj/xcuserdata/wangzhi.xcuserdatad/xcschemes/IQKeyboardManager.xcscheme
  17. 1 1
      KulexiuForStudent/Pods/Pods.xcodeproj/xcuserdata/wangzhi.xcuserdatad/xcschemes/JCore.xcscheme
  18. 1 1
      KulexiuForStudent/Pods/Pods.xcodeproj/xcuserdata/wangzhi.xcuserdatad/xcschemes/JPush.xcscheme
  19. 1 1
      KulexiuForStudent/Pods/Pods.xcodeproj/xcuserdata/wangzhi.xcuserdatad/xcschemes/JXCategoryView.xcscheme
  20. 1 1
      KulexiuForStudent/Pods/Pods.xcodeproj/xcuserdata/wangzhi.xcuserdatad/xcschemes/JXPagingView.xcscheme
  21. 1 1
      KulexiuForStudent/Pods/Pods.xcodeproj/xcuserdata/wangzhi.xcuserdatad/xcschemes/MBProgressHUD.xcscheme
  22. 1 1
      KulexiuForStudent/Pods/Pods.xcodeproj/xcuserdata/wangzhi.xcuserdatad/xcschemes/MJExtension.xcscheme
  23. 1 1
      KulexiuForStudent/Pods/Pods.xcodeproj/xcuserdata/wangzhi.xcuserdatad/xcschemes/MJRefresh.xcscheme
  24. 1 1
      KulexiuForStudent/Pods/Pods.xcodeproj/xcuserdata/wangzhi.xcuserdatad/xcschemes/Masonry.xcscheme
  25. 1 1
      KulexiuForStudent/Pods/Pods.xcodeproj/xcuserdata/wangzhi.xcuserdatad/xcschemes/Pods-KulexiuForStudent-KulexiuForStudentUITests.xcscheme
  26. 1 1
      KulexiuForStudent/Pods/Pods.xcodeproj/xcuserdata/wangzhi.xcuserdatad/xcschemes/Pods-KulexiuForStudent.xcscheme
  27. 1 1
      KulexiuForStudent/Pods/Pods.xcodeproj/xcuserdata/wangzhi.xcuserdatad/xcschemes/Pods-KulexiuForStudentTests.xcscheme
  28. 1 1
      KulexiuForStudent/Pods/Pods.xcodeproj/xcuserdata/wangzhi.xcuserdatad/xcschemes/RSKImageCropper.xcscheme
  29. 1 1
      KulexiuForStudent/Pods/Pods.xcodeproj/xcuserdata/wangzhi.xcuserdatad/xcschemes/Reachability.xcscheme
  30. 1 1
      KulexiuForStudent/Pods/Pods.xcodeproj/xcuserdata/wangzhi.xcuserdatad/xcschemes/SDWebImage.xcscheme
  31. 1 1
      KulexiuForStudent/Pods/Pods.xcodeproj/xcuserdata/wangzhi.xcuserdatad/xcschemes/SSZipArchive.xcscheme
  32. 1 1
      KulexiuForStudent/Pods/Pods.xcodeproj/xcuserdata/wangzhi.xcuserdatad/xcschemes/SocketRocket.xcscheme
  33. 1 1
      KulexiuForStudent/Pods/Pods.xcodeproj/xcuserdata/wangzhi.xcuserdatad/xcschemes/Whiteboard-Whiteboard.xcscheme
  34. 1 1
      KulexiuForStudent/Pods/Pods.xcodeproj/xcuserdata/wangzhi.xcuserdatad/xcschemes/Whiteboard.xcscheme
  35. 1 1
      KulexiuForStudent/Pods/Pods.xcodeproj/xcuserdata/wangzhi.xcuserdatad/xcschemes/YYModel.xcscheme

+ 21 - 1
KulexiuForStudent/KulexiuForStudent.xcodeproj/project.pbxproj

@@ -657,6 +657,8 @@
 		BC9AA0DF2ABC434900CD954D /* KSCustomLoadingView.xib in Resources */ = {isa = PBXBuildFile; fileRef = BC9AA0DB2ABC434900CD954D /* KSCustomLoadingView.xib */; };
 		BCA1136828A3A5CF007FAFB9 /* Accelerate.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = BCA1136728A3A5CF007FAFB9 /* Accelerate.framework */; };
 		BCA193B8282B6094004A585D /* RecentCourseModel.m in Sources */ = {isa = PBXBuildFile; fileRef = BCA193B7282B6094004A585D /* RecentCourseModel.m */; };
+		BCA336992C942B280074DF75 /* KSSourceDownloadAlert.m in Sources */ = {isa = PBXBuildFile; fileRef = BCA336962C942B270074DF75 /* KSSourceDownloadAlert.m */; };
+		BCA3369A2C942B280074DF75 /* KSSourceDownloadAlert.xib in Resources */ = {isa = PBXBuildFile; fileRef = BCA336972C942B280074DF75 /* KSSourceDownloadAlert.xib */; };
 		BCA353F12859BB2900377661 /* MusicRoomCourseCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = BCA353EF2859BB2700377661 /* MusicRoomCourseCell.xib */; };
 		BCA353F22859BB2900377661 /* MusicRoomCourseCell.m in Sources */ = {isa = PBXBuildFile; fileRef = BCA353F02859BB2900377661 /* MusicRoomCourseCell.m */; };
 		BCB574EC2BC4D643005EE78F /* cloudCourse_Ani.json in Resources */ = {isa = PBXBuildFile; fileRef = BCB574EB2BC4D643005EE78F /* cloudCourse_Ani.json */; };
@@ -833,6 +835,8 @@
 		BCC583D128A9EC6400BAB4CF /* cloud_animation_2.png in Resources */ = {isa = PBXBuildFile; fileRef = BCC583B228A9EC6400BAB4CF /* cloud_animation_2.png */; };
 		BCC583D228A9EC6400BAB4CF /* cloud_animation.json in Resources */ = {isa = PBXBuildFile; fileRef = BCC583B328A9EC6400BAB4CF /* cloud_animation.json */; };
 		BCC5841E28AA545B00BAB4CF /* cloud_animation_29.png in Resources */ = {isa = PBXBuildFile; fileRef = BCC5841D28AA545B00BAB4CF /* cloud_animation_29.png */; };
+		BCC9A7B62C955CB500F5D005 /* KSPlatformDownloadAlert.m in Sources */ = {isa = PBXBuildFile; fileRef = BCC9A7B52C955CB500F5D005 /* KSPlatformDownloadAlert.m */; };
+		BCC9A7B82C955CBB00F5D005 /* KSPlatformDownloadAlert.xib in Resources */ = {isa = PBXBuildFile; fileRef = BCC9A7B72C955CBB00F5D005 /* KSPlatformDownloadAlert.xib */; };
 		BCCC361A2AAF0D77000D60CA /* INSSettingBodyView.m in Sources */ = {isa = PBXBuildFile; fileRef = BCCC36192AAF0D77000D60CA /* INSSettingBodyView.m */; };
 		BCCC361C2AAF0D7C000D60CA /* INSSettingBodyView.xib in Resources */ = {isa = PBXBuildFile; fileRef = BCCC361B2AAF0D7C000D60CA /* INSSettingBodyView.xib */; };
 		BCCC36202AAF0EDF000D60CA /* SettingBottomView.m in Sources */ = {isa = PBXBuildFile; fileRef = BCCC361D2AAF0EDE000D60CA /* SettingBottomView.m */; };
@@ -2045,6 +2049,9 @@
 		BCA1136728A3A5CF007FAFB9 /* Accelerate.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Accelerate.framework; path = System/Library/Frameworks/Accelerate.framework; sourceTree = SDKROOT; };
 		BCA193B6282B6094004A585D /* RecentCourseModel.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RecentCourseModel.h; sourceTree = "<group>"; };
 		BCA193B7282B6094004A585D /* RecentCourseModel.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RecentCourseModel.m; sourceTree = "<group>"; };
+		BCA336962C942B270074DF75 /* KSSourceDownloadAlert.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = KSSourceDownloadAlert.m; sourceTree = "<group>"; };
+		BCA336972C942B280074DF75 /* KSSourceDownloadAlert.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = KSSourceDownloadAlert.xib; sourceTree = "<group>"; };
+		BCA336982C942B280074DF75 /* KSSourceDownloadAlert.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = KSSourceDownloadAlert.h; sourceTree = "<group>"; };
 		BCA353EE2859BB2600377661 /* MusicRoomCourseCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MusicRoomCourseCell.h; sourceTree = "<group>"; };
 		BCA353EF2859BB2700377661 /* MusicRoomCourseCell.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = MusicRoomCourseCell.xib; sourceTree = "<group>"; };
 		BCA353F02859BB2900377661 /* MusicRoomCourseCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MusicRoomCourseCell.m; sourceTree = "<group>"; };
@@ -2330,6 +2337,9 @@
 		BCC583B228A9EC6400BAB4CF /* cloud_animation_2.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = cloud_animation_2.png; sourceTree = "<group>"; };
 		BCC583B328A9EC6400BAB4CF /* cloud_animation.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = cloud_animation.json; sourceTree = "<group>"; };
 		BCC5841D28AA545B00BAB4CF /* cloud_animation_29.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = cloud_animation_29.png; sourceTree = "<group>"; };
+		BCC9A7B42C955CB500F5D005 /* KSPlatformDownloadAlert.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = KSPlatformDownloadAlert.h; sourceTree = "<group>"; };
+		BCC9A7B52C955CB500F5D005 /* KSPlatformDownloadAlert.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = KSPlatformDownloadAlert.m; sourceTree = "<group>"; };
+		BCC9A7B72C955CBB00F5D005 /* KSPlatformDownloadAlert.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = KSPlatformDownloadAlert.xib; sourceTree = "<group>"; };
 		BCCC36182AAF0D77000D60CA /* INSSettingBodyView.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = INSSettingBodyView.h; sourceTree = "<group>"; };
 		BCCC36192AAF0D77000D60CA /* INSSettingBodyView.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = INSSettingBodyView.m; sourceTree = "<group>"; };
 		BCCC361B2AAF0D7C000D60CA /* INSSettingBodyView.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = INSSettingBodyView.xib; sourceTree = "<group>"; };
@@ -4536,6 +4546,12 @@
 				275FA1B927E7351500CFEA2E /* KSLocalWebViewController.m */,
 				275FA1D527E7351800CFEA2E /* KSBaseWKWebViewController.h */,
 				275FA1CE27E7351700CFEA2E /* KSBaseWKWebViewController.m */,
+				BCC9A7B42C955CB500F5D005 /* KSPlatformDownloadAlert.h */,
+				BCC9A7B52C955CB500F5D005 /* KSPlatformDownloadAlert.m */,
+				BCC9A7B72C955CBB00F5D005 /* KSPlatformDownloadAlert.xib */,
+				BCA336982C942B280074DF75 /* KSSourceDownloadAlert.h */,
+				BCA336962C942B270074DF75 /* KSSourceDownloadAlert.m */,
+				BCA336972C942B280074DF75 /* KSSourceDownloadAlert.xib */,
 				BC0D95152AC280CA00E54D3F /* KSWebLoadRefreshView.h */,
 				BC0D95172AC280CA00E54D3F /* KSWebLoadRefreshView.m */,
 				BC0D95162AC280CA00E54D3F /* KSWebLoadRefreshView.xib */,
@@ -6128,7 +6144,7 @@
 			isa = PBXProject;
 			attributes = {
 				BuildIndependentTargetsInParallel = 1;
-				LastUpgradeCheck = 1530;
+				LastUpgradeCheck = 1540;
 				TargetAttributes = {
 					275E8AA427E18F8800DD3F6E = {
 						CreatedOnToolsVersion = 13.2.1;
@@ -6250,6 +6266,7 @@
 				2723B62F27F157D500E0B90B /* ChatComplainBodyView.xib in Resources */,
 				BC71D254288804CD0010F14B /* img_4.png in Resources */,
 				2723B62127F157D500E0B90B /* NoticeEditBodyView.xib in Resources */,
+				BCC9A7B82C955CBB00F5D005 /* KSPlatformDownloadAlert.xib in Resources */,
 				BC802DB328BC70370079E350 /* HomeHotTalentCell.xib in Resources */,
 				BC42CAA52BEC8272001F076E /* RhythmChooseView.xib in Resources */,
 				BC2DFF5B28C097D60056105A /* talentAnimation.json in Resources */,
@@ -6323,6 +6340,7 @@
 				BCFDA65528BCA2000022B497 /* accomapny_animation_0.png in Resources */,
 				BC3BF6412B9FE92600831494 /* ShareFunctionView.xib in Resources */,
 				BCC583C828A9EC6400BAB4CF /* cloud_animation_10.png in Resources */,
+				BCA3369A2C942B280074DF75 /* KSSourceDownloadAlert.xib in Resources */,
 				BCC583C328A9EC6400BAB4CF /* cloud_animation_14.png in Resources */,
 				BC8C2C5B2823F57100FBA5D5 /* AddressBottomView.xib in Resources */,
 				BC71D261288804CD0010F14B /* img_50.png in Resources */,
@@ -6915,6 +6933,7 @@
 				BCB5B2D52ABB1E13005BF25D /* KSEmptyStatusView.m in Sources */,
 				BCC0F6ED2A8CE4AF00C4EFA4 /* ZoomControl.m in Sources */,
 				BCC409002AFCE6B500C60249 /* VideoCoverChooseView.m in Sources */,
+				BCA336992C942B280074DF75 /* KSSourceDownloadAlert.m in Sources */,
 				BCF472E72AB019CD0032BE16 /* TenantDarkViewController.m in Sources */,
 				BC83A83E2AD28A9F0033D48B /* TenantNotiferNavView.m in Sources */,
 				BC106C032A933829000759A9 /* TXLiveMessageOpenLive.m in Sources */,
@@ -7069,6 +7088,7 @@
 				BCC0F6642A8CD8F500C4EFA4 /* TXDanBottomView.m in Sources */,
 				BC119259280FA85300A716F7 /* HomeworkListCell.m in Sources */,
 				BC38C45E2AFA095D00ABFCC2 /* MineWorksBodyView.m in Sources */,
+				BCC9A7B62C955CB500F5D005 /* KSPlatformDownloadAlert.m in Sources */,
 				BCC0F6592A8CD8F500C4EFA4 /* TXChatAreaView.m in Sources */,
 				2723B5CD27F157BE00E0B90B /* GroupListModel.m in Sources */,
 				2723B63327F157D500E0B90B /* ChatComplainBodyView.m in Sources */,

+ 1 - 1
KulexiuForStudent/KulexiuForStudent.xcodeproj/xcshareddata/xcschemes/KulexiuForStudent.xcscheme

@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <Scheme
-   LastUpgradeVersion = "1530"
+   LastUpgradeVersion = "1540"
    version = "1.3">
    <BuildAction
       parallelizeBuildables = "YES"

+ 22 - 0
KulexiuForStudent/KulexiuForStudent/Assets.xcassets/download_topLayer.imageset/Contents.json

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

BIN
KulexiuForStudent/KulexiuForStudent/Assets.xcassets/download_topLayer.imageset/download_topLayer@2x.png


BIN
KulexiuForStudent/KulexiuForStudent/Assets.xcassets/download_topLayer.imageset/download_topLayer@3x.png


+ 236 - 66
KulexiuForStudent/KulexiuForStudent/Common/Base/WebView/KSBaseWKWebViewController.m

@@ -37,6 +37,8 @@
 
 #import "KSNewAlertView.h"
 #import "KSLogManager.h"
+#import "KSSourceDownloadAlert.h"
+#import "KSPlatformDownloadAlert.h"
 
 typedef NS_ENUM(NSInteger, CHOOSETYPE) {
     CHOOSETYPE_XML,
@@ -72,12 +74,19 @@ typedef NS_ENUM(NSInteger, CHOOSETYPE) {
 
 @property (nonatomic, strong) KSUMShareManager *shareManager;
 
-@property (nonatomic, assign) BOOL isDownloadFile;
 
 @property (nonatomic, strong) KSNewAlertView *wifiAlert;
 // 是否需要重新加载
 @property (nonatomic, assign) BOOL needReload;
 
+@property (nonatomic, assign) BOOL isDownloadFile;
+
+@property (nonatomic, strong) NSDictionary *downloadParm;
+// 下载文件地址
+@property (nonatomic, strong) NSURL *downloadFileUrl;
+//文件预览(写全局变量,否则操作不成功)
+@property (nonatomic, strong) UIDocumentInteractionController *documentVC;
+
 @end
 
 @implementation KSBaseWKWebViewController
@@ -381,6 +390,10 @@ typedef NS_ENUM(NSInteger, CHOOSETYPE) {
             }];
         }
     }
+    else if ([[parm ks_stringValueForKey:@"api"] isEqualToString:@"downloadFile"]) {
+        NSString *url = [[parm ks_dictionaryValueForKey:@"content"] ks_stringValueForKey:@"downloadUrl"];
+        [self downloadFileWithUrl:url parm:parm];
+    }
     // 回调是否刘海屏
     else if ([[parm ks_stringValueForKey:@"api"] isEqualToString:@"isSpecialShapedScreen"]) {
         BOOL isShapedScreen = iPhoneXSafeTopMargin > 0 ? YES : NO;
@@ -712,9 +725,87 @@ typedef NS_ENUM(NSInteger, CHOOSETYPE) {
         [sendParm setValue:content forKey:@"content"];
         [self postMessage:sendParm];
     }
+}
+
+- (void)downloadFileWithUrl:(NSString *)fileUrl parm:(NSDictionary *)parm {
+    [LOADING_MANAGER showCustomLoading:@"文件下载中"];
+    [KSNetworkingManager downloadFileRequestWithFileUrl:fileUrl progress:^(int64_t bytesRead, int64_t totalBytes) {
+        // 显示进度
+        NSInteger progress = (NSInteger)(bytesRead*1.0 / totalBytes) * 100;
+        NSString *tipsString = [NSString stringWithFormat:@"文件下载中\n%zd%%",progress];
+        dispatch_main_async_safe(^{
+            [LOADING_MANAGER showCustomLoading:tipsString];
+        });
+    } success:^(NSURL * _Nonnull fileUrl) {
+        [LOADING_MANAGER removeCustomLoading];
+        // 修改文件名
+        NSURL *saveUrl = fileUrl;
+        NSDictionary *content = [parm ks_dictionaryValueForKey:@"content"];
+        NSString *fileName = [content ks_stringValueForKey:@"fileName"];
+        if (![NSString isEmptyString:fileName]) { // 重命名
+            saveUrl = [self renameFile:fileUrl withNewName:fileName];
+        }
+        [self saveFileWithPath:saveUrl sendParm:parm];
+    } faliure:^(NSError * _Nonnull error) {
+        [LOADING_MANAGER removeCustomLoading];
+        [self downloadCallback:NO withParm:parm];
+    }];
+}
+
+- (void)downloadCallback:(BOOL)isSuccess withParm:(NSDictionary *)parm {
+    NSMutableDictionary *sendParm = [NSMutableDictionary dictionaryWithDictionary:parm];
+    NSMutableDictionary *content = [NSMutableDictionary dictionaryWithDictionary:[parm ks_dictionaryValueForKey:@"content"]];
+    [content setValue:@(isSuccess) forKey:@"isSuccess"];
+    [sendParm setValue:content forKey:@"content"];
+    [self postMessage:sendParm];
+}
+
+- (NSURL *)renameFile:(NSURL *)fileUrl withNewName:(NSString *)fileName {
+    // 获取文件的路径
+    NSURL *directoryURL = [fileUrl URLByDeletingLastPathComponent];
+    // 旧文件名
+    NSString *oldFileName = [fileUrl lastPathComponent];
+    NSString *fileExtension = [oldFileName pathExtension];
+    // 当前时间戳
+    NSTimeInterval interval = [[NSDate date] timeIntervalSince1970] *1000;
+    // 构建新的文件名
+    NSString *newFileName = [NSString stringWithFormat:@"%.0f_%@.%@", interval, fileName, fileExtension];
+    // 构建新文件的完整 URL
+    NSURL *newURL = [directoryURL URLByAppendingPathComponent:newFileName];
+    
+    // 使用 NSFileManager 移动文件以重命名
+    NSFileManager *fileManager = [NSFileManager defaultManager];
+    
+    // 如果存在newURL 移除
+    if ([fileManager fileExistsAtPath:[newURL path]]) {
+        [fileManager removeItemAtURL:newURL error:nil];
+    }
     
+    NSError *error = nil;
+    BOOL success = [fileManager moveItemAtURL:fileUrl toURL:newURL error:&error];
+    if (success) {
+        return newURL;
+    }
+    else {
+        return fileUrl;
+    }
+}
+
+- (void)saveFileWithPath:(NSURL *)fileUrl sendParm:(NSDictionary *)parm {
+    self.downloadParm = parm;
+    self.isDownloadFile = YES;
+    self.downloadFileUrl = fileUrl;
+    // 保存到文件目录下
+    KSDocumentViewController *documentPickerVC = [[KSDocumentViewController alloc] initWithURL:fileUrl inMode:UIDocumentPickerModeExportToService];
+    documentPickerVC.buttonColor = THEMECOLOR;
+    // 设置代理
+    documentPickerVC.delegate = self;
+    // 设置模态弹出方式
+    documentPickerVC.modalPresentationStyle = UIModalPresentationFormSheet;
+    [self.navigationController presentViewController:documentPickerVC animated:YES completion:nil];
 }
 
+
 - (void)afterCheckCameraCheckMic:(PREMISSIONTYPE)cameraType parm:(NSDictionary *)sourceParm {
     
     [RecordCheckManager checkMicPermissionAvaiableCallback:^(PREMISSIONTYPE type) {
@@ -842,8 +933,9 @@ typedef NS_ENUM(NSInteger, CHOOSETYPE) {
 
 - (void)saveFileToPhone:(NSURL *)fileUrl {
     self.isDownloadFile = YES;
-
-    UIDocumentPickerViewController *documentPicker = [[UIDocumentPickerViewController alloc] initWithURL:fileUrl inMode:UIDocumentPickerModeExportToService];
+    self.downloadFileUrl = fileUrl;
+    KSDocumentViewController *documentPicker = [[KSDocumentViewController alloc] initWithURL:fileUrl inMode:UIDocumentPickerModeExportToService];
+    documentPicker.buttonColor = THEMECOLOR;
     documentPicker.delegate = self;
     documentPicker.modalPresentationStyle = UIModalPresentationFormSheet;
     [self presentViewController:documentPicker animated:YES completion:nil];
@@ -878,6 +970,7 @@ typedef NS_ENUM(NSInteger, CHOOSETYPE) {
     self.fileChooseType = fileTyle;
     NSArray *documentTypes = @[@"public.content", @"public.text", @"public.source-code", @"public.image", @"public.audio", @"public.audiovisual-content", @"com.adobe.pdf", @"com.apple.keynote.key", @"com.microsoft.word.doc", @"com.microsoft.excel.xls", @"com.microsoft.powerpoint.ppt"];
     KSDocumentViewController *documentPickerViewController = [[KSDocumentViewController alloc] initWithDocumentTypes:documentTypes inMode:UIDocumentPickerModeImport];
+    documentPickerViewController.buttonColor = THEMECOLOR;
     documentPickerViewController.delegate = self;
     documentPickerViewController.modalPresentationStyle = UIModalPresentationFullScreen;
     [self presentViewController:documentPickerViewController animated:YES completion:nil];
@@ -1579,78 +1672,51 @@ typedef NS_ENUM(NSInteger, CHOOSETYPE) {
 - (void)documentPickerWasCancelled:(UIDocumentPickerViewController *)controller {
     if (self.isDownloadFile) {
         self.isDownloadFile = NO;
+        if (self.downloadParm) {
+            [self downloadCallback:NO withParm:self.downloadParm];
+            self.downloadParm = nil;
+        }
     }
     else {
         [self fileChooseErrorCallback];
     }
 }
 
-- (void)fileChooseErrorCallback {
-    if (self.chooseFileParm) { // 回调
-        [self.chooseFileParm setValue:@"" forKey:@"fileUrl"];
-        [self postMessage:self.chooseFileParm];
-        self.chooseFileParm = nil;
-    }
-}
-
-
-- (void)uploadFile:(NSString *)fileName fileUrl:(NSString *)fileUrl {
-    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
-        [LOADING_MANAGER showHUD];
-        NSString *suffix = [NSString stringWithFormat:@".%@",[[fileName componentsSeparatedByString:@"."] lastObject]];
-        NSData *fileData = [NSData dataWithContentsOfURL:[NSURL fileURLWithPath:fileUrl]];
-        [UPLOAD_MANAGER configWithfilePath:@"/user/"];
-        [UPLOAD_MANAGER uploadFile:fileData fileName:@"file" fileSuffix:suffix progress:^(int64_t bytesWritten, int64_t totalBytes) {
-            int progress = (int)(bytesWritten / totalBytes * 100);
-            __block NSString *tipsMessage = [NSString stringWithFormat:@"上传中 %d%%",progress];
-            dispatch_main_async_safe(^{
-                [LOADING_MANAGER.loadingView setDisplayText:tipsMessage];
-            });
-        } successCallback:^(NSMutableArray * _Nonnull fileUrlArray) {
-            [LOADING_MANAGER removeHUD];
-            NSString *fileUrl = [fileUrlArray lastObject];
-            if (self.chooseFileParm) { // 回调
-                [self.chooseFileParm setValue:fileUrl forKey:@"fileUrl"];
-                [self postMessage:self.chooseFileParm];
-                self.chooseFileParm = nil;
-            }
-        } faliure:^(NSError * _Nullable error, NSString * _Nullable descMessaeg) {
-            [LOADING_MANAGER removeHUD];
-            [LOADING_MANAGER MBShowAUTOHidingInWindow:descMessaeg];
-            [self fileChooseErrorCallback];
-        }];
-    });
-}
-
-- (CGFloat)getFileSize:(NSURL *)fileUrl {
-    NSFileManager *fileManager = [NSFileManager defaultManager];
-    float filesize = -1.0;
-    NSString *path = fileUrl.path;
-    if ([fileManager fileExistsAtPath:path]) {
-        NSDictionary *fileDic = [fileManager attributesOfItemAtPath:path error:nil];//获取文件的属性
-        unsigned long long size = [[fileDic objectForKey:NSFileSize] longLongValue];
-        filesize = 1.0*size/1024/1024;
-    }
-    return filesize;
-}
-
-
-#pragma mark - UIDocumentInteractionControllerDelegate
--(UIViewController*)documentInteractionControllerViewControllerForPreview:(UIDocumentInteractionController*)controller{
-    return self;
-}
--(UIView*)documentInteractionControllerViewForPreview:(UIDocumentInteractionController*)controller {
-    return self.view;
-}
--(CGRect)documentInteractionControllerRectForPreview:(UIDocumentInteractionController*)controller {
-    return self.view.frame;
-}
-#pragma mark - UIDocumentPickerDelegate
 - (void)documentPicker:(UIDocumentPickerViewController *)controller didPickDocumentsAtURLs:(NSArray <NSURL *>*)urls {
     if (self.isDownloadFile) {
         self.isDownloadFile = NO;
-        //保存成功
-       [LOADING_MANAGER MBShowAUTOHidingInWindow:@"保存成功"];
+        [self downloadCallback:YES withParm:self.downloadParm];
+        self.downloadParm = nil;
+        
+        NSURL *descUrl = [urls firstObject];
+        NSString *desc = [descUrl absoluteString];
+        
+        if ([UserDefaultObjectForKey(TENANT_ID) integerValue] > 0) { // 机构
+            KSSourceDownloadAlert *alertView = [KSSourceDownloadAlert shareInstance];
+            [alertView configWithDesc:desc];
+            [alertView actionCallbackCancel:^{
+                
+            } copyCallback:^{
+                [self copyAction:desc];
+            } sure:^{
+                [self openFileSource:descUrl];
+            }];
+            [alertView showAlert];
+        }
+        else {
+            
+            KSPlatformDownloadAlert *alertView = [KSPlatformDownloadAlert shareInstance];
+            [alertView configWithDesc:desc];
+            [alertView actionCallbackCancel:^{
+                
+            } copyCallback:^{
+                [self copyAction:desc];
+            } sure:^{
+                [self openFileSource:descUrl];
+            }];
+            [alertView showAlert];
+        }
+        
     }
     else {
         NSURL *url =  [urls lastObject];
@@ -1720,6 +1786,110 @@ typedef NS_ENUM(NSInteger, CHOOSETYPE) {
     }
 }
 
+- (void)openFileSource:(NSURL *)path {
+    if (self.downloadFileUrl) {
+        [self displayFileWithUrl:path];
+    }
+    else {
+        // 开始访问权限
+        BOOL fileUrlAuthozied = [path startAccessingSecurityScopedResource];
+        
+        if (fileUrlAuthozied) {
+            // 通过 NSFileCoordinator 来协调读取
+            NSFileCoordinator *fileCoordinator = [[NSFileCoordinator alloc] init];
+            NSError *error = nil;
+            
+            [fileCoordinator coordinateReadingItemAtURL:path options:0 error:&error byAccessor:^(NSURL *newURL) {
+                // 打开文档
+                [self displayFileWithUrl:newURL];
+            }];
+            // 释放权限
+            [path stopAccessingSecurityScopedResource];
+        } else {
+            [LOADING_MANAGER MBShowAUTOHidingInWindow:@"无法访问文件"];
+        }
+    }
+}
+
+- (void)displayFileWithUrl:(NSURL *)url {
+    // 打开文档
+    self.documentVC = [UIDocumentInteractionController interactionControllerWithURL:url];
+    // 2. 设置代理(如果需要处理特定交互事件)
+    self.documentVC.delegate = self;
+    
+    // 3. 显示“打开方式”菜单或文件预览
+    // 从指定的视图呈现操作菜单
+    [self.documentVC presentOptionsMenuFromRect:self.view.bounds inView:self.view animated:YES];
+}
+
+- (void)copyAction:(NSString *)desc {
+    // 复制
+    UIPasteboard *pasteboard = [UIPasteboard generalPasteboard];
+    pasteboard.string = [NSString returnNoNullStringWithString:desc];
+    [LOADING_MANAGER MBShowAUTOHidingInWindow:@"复制成功"];
+}
+
+- (void)fileChooseErrorCallback {
+    if (self.chooseFileParm) { // 回调
+        [self.chooseFileParm setValue:@"" forKey:@"fileUrl"];
+        [self postMessage:self.chooseFileParm];
+        self.chooseFileParm = nil;
+    }
+}
+
+
+- (void)uploadFile:(NSString *)fileName fileUrl:(NSString *)fileUrl {
+    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
+        [LOADING_MANAGER showHUD];
+        NSString *suffix = [NSString stringWithFormat:@".%@",[[fileName componentsSeparatedByString:@"."] lastObject]];
+        NSData *fileData = [NSData dataWithContentsOfURL:[NSURL fileURLWithPath:fileUrl]];
+        [UPLOAD_MANAGER configWithfilePath:@"/user/"];
+        [UPLOAD_MANAGER uploadFile:fileData fileName:@"file" fileSuffix:suffix progress:^(int64_t bytesWritten, int64_t totalBytes) {
+            int progress = (int)(bytesWritten / totalBytes * 100);
+            __block NSString *tipsMessage = [NSString stringWithFormat:@"上传中 %d%%",progress];
+            dispatch_main_async_safe(^{
+                [LOADING_MANAGER.loadingView setDisplayText:tipsMessage];
+            });
+        } successCallback:^(NSMutableArray * _Nonnull fileUrlArray) {
+            [LOADING_MANAGER removeHUD];
+            NSString *fileUrl = [fileUrlArray lastObject];
+            if (self.chooseFileParm) { // 回调
+                [self.chooseFileParm setValue:fileUrl forKey:@"fileUrl"];
+                [self postMessage:self.chooseFileParm];
+                self.chooseFileParm = nil;
+            }
+        } faliure:^(NSError * _Nullable error, NSString * _Nullable descMessaeg) {
+            [LOADING_MANAGER removeHUD];
+            [LOADING_MANAGER MBShowAUTOHidingInWindow:descMessaeg];
+            [self fileChooseErrorCallback];
+        }];
+    });
+}
+
+- (CGFloat)getFileSize:(NSURL *)fileUrl {
+    NSFileManager *fileManager = [NSFileManager defaultManager];
+    float filesize = -1.0;
+    NSString *path = fileUrl.path;
+    if ([fileManager fileExistsAtPath:path]) {
+        NSDictionary *fileDic = [fileManager attributesOfItemAtPath:path error:nil];//获取文件的属性
+        unsigned long long size = [[fileDic objectForKey:NSFileSize] longLongValue];
+        filesize = 1.0*size/1024/1024;
+    }
+    return filesize;
+}
+
+
+#pragma mark - UIDocumentInteractionControllerDelegate
+-(UIViewController*)documentInteractionControllerViewControllerForPreview:(UIDocumentInteractionController*)controller{
+    return self;
+}
+-(UIView*)documentInteractionControllerViewForPreview:(UIDocumentInteractionController*)controller {
+    return self.view;
+}
+-(CGRect)documentInteractionControllerRectForPreview:(UIDocumentInteractionController*)controller {
+    return self.view.frame;
+}
+
 #pragma mark ---- 镜像和投屏检测
 
 - (void)captureViewTips:(NSNotification *)notification {

+ 25 - 0
KulexiuForStudent/KulexiuForStudent/Common/Base/WebView/KSPlatformDownloadAlert.h

@@ -0,0 +1,25 @@
+//
+//  KSPlatformDownloadAlert.h
+//  KulexiuForStudent
+//
+//  Created by 王智 on 2024/9/14.
+//
+
+#import <UIKit/UIKit.h>
+#import "KSSourceDownloadAlert.h"
+
+NS_ASSUME_NONNULL_BEGIN
+
+@interface KSPlatformDownloadAlert : UIView
+
++ (instancetype)shareInstance;
+
+- (void)configWithDesc:(NSString *)desc;
+
+- (void)actionCallbackCancel:(DownloadSaveTipsCallback)cancel copyCallback:(DownloadSaveTipsCallback)copyBlock sure:(DownloadSaveTipsCallback)sure;
+
+- (void)showAlert;
+
+@end
+
+NS_ASSUME_NONNULL_END

+ 94 - 0
KulexiuForStudent/KulexiuForStudent/Common/Base/WebView/KSPlatformDownloadAlert.m

@@ -0,0 +1,94 @@
+//
+//  KSPlatformDownloadAlert.m
+//  KulexiuForStudent
+//
+//  Created by 王智 on 2024/9/14.
+//
+
+#import "KSPlatformDownloadAlert.h"
+
+@interface KSPlatformDownloadAlert ()
+
+@property (weak, nonatomic) IBOutlet UIView *containerView;
+
+@property (weak, nonatomic) IBOutlet UILabel *descLabel;
+
+@property (nonatomic, strong) UITapGestureRecognizer *gesture;
+
+@property (nonatomic, copy) DownloadSaveTipsCallback cancelCallback;
+
+@property (nonatomic, copy) DownloadSaveTipsCallback copyBlock;
+
+@property (nonatomic, copy) DownloadSaveTipsCallback sureCallback;
+
+@end
+
+@implementation KSPlatformDownloadAlert
+
+
++ (instancetype)shareInstance {
+    KSPlatformDownloadAlert *view = [[[NSBundle mainBundle] loadNibNamed:@"KSPlatformDownloadAlert" owner:nil options:nil] firstObject];
+    return view;
+}
+
+- (void)configWithDesc:(NSString *)desc {
+    if ([NSString isEmptyString:desc]) {
+        desc = @"";
+    }
+    self.descLabel.text = desc;
+}
+
+
+- (void)actionCallbackCancel:(DownloadSaveTipsCallback)cancel copyCallback:(DownloadSaveTipsCallback)copyBlock sure:(DownloadSaveTipsCallback)sure {
+    if (cancel) {
+        self.cancelCallback = cancel;
+    }
+    if (copyBlock) {
+        self.copyBlock = copyBlock;
+    }
+    if (sure) {
+        self.sureCallback = sure;
+    }
+}
+
+- (void)showAlert {
+    UIView *displayView = [NSObject getKeyWindow];
+    [displayView addSubview:self];
+    [self mas_makeConstraints:^(MASConstraintMaker *make) {
+        make.left.right.top.bottom.mas_equalTo(displayView);
+    }];
+}
+
+- (IBAction)copyActipn:(id)sender {
+    if (self.copyBlock) {
+        self.copyBlock();
+    }
+}
+
+
+- (void)removeAlert {
+    [self removeFromSuperview];
+
+}
+- (IBAction)cancelAction:(id)sender {
+    [self removeAlert];
+    if (self.cancelCallback) {
+        self.cancelCallback();
+    }
+}
+
+- (IBAction)sureAction:(id)sender {
+    [self removeAlert];
+    if (self.sureCallback) {
+        self.sureCallback();
+    }
+}
+/*
+// Only override drawRect: if you perform custom drawing.
+// An empty implementation adversely affects performance during animation.
+- (void)drawRect:(CGRect)rect {
+    // Drawing code
+}
+*/
+
+@end

+ 178 - 0
KulexiuForStudent/KulexiuForStudent/Common/Base/WebView/KSPlatformDownloadAlert.xib

@@ -0,0 +1,178 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="32700.99.1234" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES">
+    <device id="retina6_12" orientation="portrait" appearance="light"/>
+    <dependencies>
+        <deployment identifier="iOS"/>
+        <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="22685"/>
+        <capability name="System colors in document resources" minToolsVersion="11.0"/>
+        <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
+    </dependencies>
+    <objects>
+        <placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner"/>
+        <placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
+        <view contentMode="scaleToFill" id="iN0-l3-epB" customClass="KSPlatformDownloadAlert">
+            <rect key="frame" x="0.0" y="0.0" width="393" height="852"/>
+            <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
+            <subviews>
+                <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="c7t-Gm-jfe">
+                    <rect key="frame" x="49" y="334" width="295" height="184"/>
+                    <subviews>
+                        <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="下载成功" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="2hf-n1-Ei5">
+                            <rect key="frame" x="20" y="15" width="65.333333333333329" height="25"/>
+                            <constraints>
+                                <constraint firstAttribute="height" constant="25" id="WjL-hX-4pp"/>
+                            </constraints>
+                            <fontDescription key="fontDescription" type="system" pointSize="16"/>
+                            <color key="textColor" red="0.1019607843" green="0.1019607843" blue="0.1019607843" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+                            <nil key="highlightedColor"/>
+                        </label>
+                        <imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="check_cancle" translatesAutoresizingMaskIntoConstraints="NO" id="Nud-jE-cnf">
+                            <rect key="frame" x="261" y="20.666666666666686" width="14" height="14"/>
+                        </imageView>
+                        <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="cy0-H2-obW">
+                            <rect key="frame" x="245" y="10" width="40" height="40"/>
+                            <constraints>
+                                <constraint firstAttribute="height" constant="40" id="IU7-Go-73m"/>
+                                <constraint firstAttribute="width" constant="40" id="wc5-h6-hWi"/>
+                            </constraints>
+                            <inset key="imageEdgeInsets" minX="0.0" minY="0.0" maxX="2.2250738585072014e-308" maxY="0.0"/>
+                            <connections>
+                                <action selector="cancelAction:" destination="iN0-l3-epB" eventType="touchUpInside" id="4Ls-Kd-bIc"/>
+                            </connections>
+                        </button>
+                        <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="文件已保存到以下地址" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="DDJ-Jw-w5Y">
+                            <rect key="frame" x="20" y="55" width="163.33333333333334" height="26"/>
+                            <constraints>
+                                <constraint firstAttribute="height" constant="26" id="WXk-xA-TBs"/>
+                            </constraints>
+                            <fontDescription key="fontDescription" type="system" pointSize="16"/>
+                            <color key="textColor" red="0.40000000000000002" green="0.40000000000000002" blue="0.40000000000000002" alpha="1" colorSpace="calibratedRGB"/>
+                            <nil key="highlightedColor"/>
+                        </label>
+                        <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="1BL-ja-AeR">
+                            <rect key="frame" x="20" y="81" width="216" height="26"/>
+                            <constraints>
+                                <constraint firstAttribute="height" constant="26" id="UBx-mC-ier"/>
+                            </constraints>
+                            <fontDescription key="fontDescription" type="system" pointSize="16"/>
+                            <color key="textColor" red="0.40000000000000002" green="0.40000000000000002" blue="0.40000000000000002" alpha="1" colorSpace="calibratedRGB"/>
+                            <nil key="highlightedColor"/>
+                        </label>
+                        <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="复制" textAlignment="right" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Dmz-RQ-nkZ">
+                            <rect key="frame" x="241" y="81" width="34" height="26"/>
+                            <constraints>
+                                <constraint firstAttribute="height" constant="26" id="jQx-R8-0Pg"/>
+                                <constraint firstAttribute="width" constant="34" id="yTB-ep-jGo"/>
+                            </constraints>
+                            <fontDescription key="fontDescription" type="system" pointSize="16"/>
+                            <color key="textColor" red="0.0039215686269999999" green="0.75686274509999996" blue="0.70980392160000005" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+                            <nil key="highlightedColor"/>
+                        </label>
+                        <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="EXr-hD-kJe">
+                            <rect key="frame" x="20" y="124" width="120" height="40"/>
+                            <constraints>
+                                <constraint firstAttribute="height" constant="40" id="XdD-oe-Y8C"/>
+                            </constraints>
+                            <fontDescription key="fontDescription" type="system" pointSize="16"/>
+                            <inset key="imageEdgeInsets" minX="0.0" minY="0.0" maxX="2.2250738585072014e-308" maxY="0.0"/>
+                            <state key="normal" title="取消">
+                                <color key="titleColor" red="0.20000000000000001" green="0.20000000000000001" blue="0.20000000000000001" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+                            </state>
+                            <userDefinedRuntimeAttributes>
+                                <userDefinedRuntimeAttribute type="number" keyPath="cornerRadius">
+                                    <real key="value" value="20"/>
+                                </userDefinedRuntimeAttribute>
+                                <userDefinedRuntimeAttribute type="number" keyPath="borderWidth">
+                                    <real key="value" value="1"/>
+                                </userDefinedRuntimeAttribute>
+                                <userDefinedRuntimeAttribute type="color" keyPath="borderColor">
+                                    <color key="value" red="0.85882352939999995" green="0.85882352939999995" blue="0.85882352939999995" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+                                </userDefinedRuntimeAttribute>
+                            </userDefinedRuntimeAttributes>
+                            <connections>
+                                <action selector="cancelAction:" destination="iN0-l3-epB" eventType="touchUpInside" id="8ga-jJ-oFT"/>
+                            </connections>
+                        </button>
+                        <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="bA6-PJ-a22">
+                            <rect key="frame" x="155" y="124" width="120" height="40"/>
+                            <color key="backgroundColor" red="0.1764705882" green="0.78039215689999997" blue="0.66666666669999997" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+                            <fontDescription key="fontDescription" type="system" weight="medium" pointSize="16"/>
+                            <inset key="imageEdgeInsets" minX="0.0" minY="0.0" maxX="2.2250738585072014e-308" maxY="0.0"/>
+                            <state key="normal" title="打开文件"/>
+                            <userDefinedRuntimeAttributes>
+                                <userDefinedRuntimeAttribute type="number" keyPath="cornerRadius">
+                                    <real key="value" value="20"/>
+                                </userDefinedRuntimeAttribute>
+                            </userDefinedRuntimeAttributes>
+                            <connections>
+                                <action selector="sureAction:" destination="iN0-l3-epB" eventType="touchUpInside" id="zv2-ae-cUz"/>
+                            </connections>
+                        </button>
+                        <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="ukm-f4-rFL">
+                            <rect key="frame" x="238" y="67" width="40" height="40"/>
+                            <constraints>
+                                <constraint firstAttribute="width" constant="40" id="Ees-TR-Sve"/>
+                                <constraint firstAttribute="height" constant="40" id="VPK-El-Cr5"/>
+                            </constraints>
+                            <inset key="imageEdgeInsets" minX="0.0" minY="0.0" maxX="2.2250738585072014e-308" maxY="0.0"/>
+                            <connections>
+                                <action selector="copyActipn:" destination="iN0-l3-epB" eventType="touchUpInside" id="8xM-bF-hsr"/>
+                            </connections>
+                        </button>
+                    </subviews>
+                    <color key="backgroundColor" systemColor="systemBackgroundColor"/>
+                    <constraints>
+                        <constraint firstItem="DDJ-Jw-w5Y" firstAttribute="top" secondItem="2hf-n1-Ei5" secondAttribute="bottom" constant="15" id="1hM-Uh-dvv"/>
+                        <constraint firstItem="EXr-hD-kJe" firstAttribute="leading" secondItem="c7t-Gm-jfe" secondAttribute="leading" constant="20" id="1z6-pp-z13"/>
+                        <constraint firstItem="2hf-n1-Ei5" firstAttribute="leading" secondItem="c7t-Gm-jfe" secondAttribute="leading" constant="20" id="2tp-mt-eJJ"/>
+                        <constraint firstItem="DDJ-Jw-w5Y" firstAttribute="leading" secondItem="c7t-Gm-jfe" secondAttribute="leading" constant="20" id="3cP-Mj-hzL"/>
+                        <constraint firstItem="1BL-ja-AeR" firstAttribute="top" secondItem="DDJ-Jw-w5Y" secondAttribute="bottom" id="5jy-qt-reM"/>
+                        <constraint firstAttribute="trailing" secondItem="bA6-PJ-a22" secondAttribute="trailing" constant="20" id="61S-2b-zxC"/>
+                        <constraint firstAttribute="height" constant="184" id="6Jj-X9-Kjg"/>
+                        <constraint firstAttribute="trailing" secondItem="Dmz-RQ-nkZ" secondAttribute="trailing" constant="20" id="7wo-e7-cTj"/>
+                        <constraint firstItem="bA6-PJ-a22" firstAttribute="height" secondItem="EXr-hD-kJe" secondAttribute="height" id="CvG-fX-A20"/>
+                        <constraint firstAttribute="bottom" secondItem="bA6-PJ-a22" secondAttribute="bottom" constant="20" id="DGm-o4-nVv"/>
+                        <constraint firstItem="Nud-jE-cnf" firstAttribute="centerY" secondItem="2hf-n1-Ei5" secondAttribute="centerY" id="FJE-px-sk7"/>
+                        <constraint firstAttribute="width" constant="295" id="Jsr-zU-YqZ"/>
+                        <constraint firstItem="bA6-PJ-a22" firstAttribute="leading" secondItem="EXr-hD-kJe" secondAttribute="trailing" constant="15" id="Kn7-px-hd2"/>
+                        <constraint firstItem="Dmz-RQ-nkZ" firstAttribute="bottom" secondItem="ukm-f4-rFL" secondAttribute="bottom" id="Mn3-4X-KMN"/>
+                        <constraint firstItem="1BL-ja-AeR" firstAttribute="leading" secondItem="DDJ-Jw-w5Y" secondAttribute="leading" id="QOd-0T-gmv"/>
+                        <constraint firstItem="Dmz-RQ-nkZ" firstAttribute="centerX" secondItem="ukm-f4-rFL" secondAttribute="centerX" id="Vzj-48-sGr"/>
+                        <constraint firstItem="Dmz-RQ-nkZ" firstAttribute="centerY" secondItem="1BL-ja-AeR" secondAttribute="centerY" id="coU-Ud-FFP"/>
+                        <constraint firstAttribute="bottom" secondItem="EXr-hD-kJe" secondAttribute="bottom" constant="20" id="eUT-Ev-P03"/>
+                        <constraint firstAttribute="trailing" secondItem="Nud-jE-cnf" secondAttribute="trailing" constant="20" id="fLJ-tU-nFH"/>
+                        <constraint firstAttribute="trailing" secondItem="cy0-H2-obW" secondAttribute="trailing" constant="10" id="nHk-hA-rIN"/>
+                        <constraint firstItem="cy0-H2-obW" firstAttribute="top" secondItem="c7t-Gm-jfe" secondAttribute="top" constant="10" id="nwU-KR-qxS"/>
+                        <constraint firstItem="bA6-PJ-a22" firstAttribute="width" secondItem="EXr-hD-kJe" secondAttribute="width" id="ryS-B6-n2o"/>
+                        <constraint firstItem="2hf-n1-Ei5" firstAttribute="top" secondItem="c7t-Gm-jfe" secondAttribute="top" constant="15" id="tRC-Ty-cDr"/>
+                        <constraint firstItem="Dmz-RQ-nkZ" firstAttribute="leading" secondItem="1BL-ja-AeR" secondAttribute="trailing" constant="5" id="uRz-hC-qZa"/>
+                    </constraints>
+                    <userDefinedRuntimeAttributes>
+                        <userDefinedRuntimeAttribute type="number" keyPath="cornerRadius">
+                            <real key="value" value="20"/>
+                        </userDefinedRuntimeAttribute>
+                    </userDefinedRuntimeAttributes>
+                </view>
+            </subviews>
+            <color key="backgroundColor" red="0.0" green="0.0" blue="0.0" alpha="0.59999999999999998" colorSpace="custom" customColorSpace="sRGB"/>
+            <constraints>
+                <constraint firstItem="c7t-Gm-jfe" firstAttribute="centerY" secondItem="iN0-l3-epB" secondAttribute="centerY" id="G2a-zB-TsK"/>
+                <constraint firstItem="c7t-Gm-jfe" firstAttribute="centerX" secondItem="iN0-l3-epB" secondAttribute="centerX" id="Zsq-XB-1at"/>
+            </constraints>
+            <nil key="simulatedTopBarMetrics"/>
+            <nil key="simulatedBottomBarMetrics"/>
+            <freeformSimulatedSizeMetrics key="simulatedDestinationMetrics"/>
+            <connections>
+                <outlet property="containerView" destination="c7t-Gm-jfe" id="IW1-jT-SlI"/>
+                <outlet property="descLabel" destination="1BL-ja-AeR" id="T6F-1E-8nZ"/>
+            </connections>
+            <point key="canvasLocation" x="31" y="20"/>
+        </view>
+    </objects>
+    <resources>
+        <image name="check_cancle" width="14" height="14"/>
+        <systemColor name="systemBackgroundColor">
+            <color white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
+        </systemColor>
+    </resources>
+</document>

+ 27 - 0
KulexiuForStudent/KulexiuForStudent/Common/Base/WebView/KSSourceDownloadAlert.h

@@ -0,0 +1,27 @@
+//
+//  KSSourceDownloadAlert.h
+//  TeacherDaya
+//
+//  Created by 王智 on 2024/9/13.
+//  Copyright © 2024 DayaMusic. All rights reserved.
+//
+
+#import <UIKit/UIKit.h>
+
+typedef void(^DownloadSaveTipsCallback)(void);
+
+NS_ASSUME_NONNULL_BEGIN
+
+@interface KSSourceDownloadAlert : UIView
+
++ (instancetype)shareInstance;
+
+- (void)configWithDesc:(NSString *)desc;
+
+- (void)actionCallbackCancel:(DownloadSaveTipsCallback)cancel copyCallback:(DownloadSaveTipsCallback)copyBlock sure:(DownloadSaveTipsCallback)sure;
+
+- (void)showAlert;
+
+@end
+
+NS_ASSUME_NONNULL_END

+ 94 - 0
KulexiuForStudent/KulexiuForStudent/Common/Base/WebView/KSSourceDownloadAlert.m

@@ -0,0 +1,94 @@
+//
+//  KSSourceDownloadAlert.m
+//  TeacherDaya
+//
+//  Created by 王智 on 2024/9/13.
+//  Copyright © 2024 DayaMusic. All rights reserved.
+//
+
+#import "KSSourceDownloadAlert.h"
+
+@interface KSSourceDownloadAlert ()
+
+@property (weak, nonatomic) IBOutlet UIView *containerView;
+
+@property (weak, nonatomic) IBOutlet UILabel *descLabel;
+
+@property (nonatomic, strong) UITapGestureRecognizer *gesture;
+
+@property (nonatomic, copy) DownloadSaveTipsCallback cancelCallback;
+
+@property (nonatomic, copy) DownloadSaveTipsCallback copyBlock;
+
+@property (nonatomic, copy) DownloadSaveTipsCallback sureCallback;
+
+@end
+
+@implementation KSSourceDownloadAlert
+
++ (instancetype)shareInstance {
+    KSSourceDownloadAlert *view = [[[NSBundle mainBundle] loadNibNamed:@"KSSourceDownloadAlert" owner:nil options:nil] firstObject];
+    return view;
+}
+
+- (void)configWithDesc:(NSString *)desc {
+    if ([NSString isEmptyString:desc]) {
+        desc = @"";
+    }
+    self.descLabel.text = desc;
+}
+
+
+- (void)actionCallbackCancel:(DownloadSaveTipsCallback)cancel copyCallback:(DownloadSaveTipsCallback)copyBlock sure:(DownloadSaveTipsCallback)sure {
+    if (cancel) {
+        self.cancelCallback = cancel;
+    }
+    if (copyBlock) {
+        self.copyBlock = copyBlock;
+    }
+    if (sure) {
+        self.sureCallback = sure;
+    }
+}
+
+- (void)showAlert {
+    UIView *displayView = [NSObject getKeyWindow];
+    [displayView addSubview:self];
+    [self mas_makeConstraints:^(MASConstraintMaker *make) {
+        make.left.right.top.bottom.mas_equalTo(displayView);
+    }];
+}
+
+- (IBAction)copyActipn:(id)sender {
+    if (self.copyBlock) {
+        self.copyBlock();
+    }
+}
+
+
+- (void)removeAlert {
+    [self removeFromSuperview];
+
+}
+- (IBAction)cancelAction:(id)sender {
+    [self removeAlert];
+    if (self.cancelCallback) {
+        self.cancelCallback();
+    }
+}
+
+- (IBAction)sureAction:(id)sender {
+    [self removeAlert];
+    if (self.sureCallback) {
+        self.sureCallback();
+    }
+}
+/*
+// Only override drawRect: if you perform custom drawing.
+// An empty implementation adversely affects performance during animation.
+- (void)drawRect:(CGRect)rect {
+    // Drawing code
+}
+*/
+
+@end

+ 187 - 0
KulexiuForStudent/KulexiuForStudent/Common/Base/WebView/KSSourceDownloadAlert.xib

@@ -0,0 +1,187 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="32700.99.1234" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES">
+    <device id="retina6_12" orientation="portrait" appearance="light"/>
+    <dependencies>
+        <deployment identifier="iOS"/>
+        <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="22685"/>
+        <capability name="System colors in document resources" minToolsVersion="11.0"/>
+        <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
+    </dependencies>
+    <objects>
+        <placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner"/>
+        <placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
+        <view contentMode="scaleToFill" id="iN0-l3-epB" customClass="KSSourceDownloadAlert">
+            <rect key="frame" x="0.0" y="0.0" width="393" height="852"/>
+            <autoresizingMask key="autoresizingMask"/>
+            <subviews>
+                <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="rhp-MD-4Jj">
+                    <rect key="frame" x="49" y="325" width="295" height="202"/>
+                    <subviews>
+                        <imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="download_topLayer" translatesAutoresizingMaskIntoConstraints="NO" id="gVg-Vm-F6v">
+                            <rect key="frame" x="0.0" y="0.0" width="295" height="49"/>
+                            <constraints>
+                                <constraint firstAttribute="width" constant="295" id="NNi-Pq-JAM"/>
+                                <constraint firstAttribute="height" constant="49" id="PpN-9D-gs9"/>
+                            </constraints>
+                        </imageView>
+                        <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="下载成功" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="lnB-qu-Uf7">
+                            <rect key="frame" x="110.66666666666666" y="20" width="74" height="25"/>
+                            <constraints>
+                                <constraint firstAttribute="height" constant="25" id="IgN-1l-ZSs"/>
+                            </constraints>
+                            <fontDescription key="fontDescription" type="system" weight="semibold" pointSize="18"/>
+                            <color key="textColor" red="0.074509803921568626" green="0.078431372549019607" blue="0.082352941176470587" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+                            <nil key="highlightedColor"/>
+                        </label>
+                        <imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="check_cancle" translatesAutoresizingMaskIntoConstraints="NO" id="Pwc-SA-BPV">
+                            <rect key="frame" x="261" y="25.666666666666686" width="14" height="14"/>
+                        </imageView>
+                        <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="XBP-di-P6K">
+                            <rect key="frame" x="245" y="10" width="40" height="40"/>
+                            <constraints>
+                                <constraint firstAttribute="height" constant="40" id="AaQ-xy-6MC"/>
+                                <constraint firstAttribute="width" constant="40" id="sUc-rj-hAl"/>
+                            </constraints>
+                            <inset key="imageEdgeInsets" minX="0.0" minY="0.0" maxX="2.2250738585072014e-308" maxY="0.0"/>
+                        </button>
+                        <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="文件已保存到以下地址" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="EP8-xw-on3">
+                            <rect key="frame" x="20" y="65" width="163.33333333333334" height="26"/>
+                            <constraints>
+                                <constraint firstAttribute="height" constant="26" id="fCS-pG-zdm"/>
+                            </constraints>
+                            <fontDescription key="fontDescription" type="system" pointSize="16"/>
+                            <color key="textColor" red="0.40000000000000002" green="0.40000000000000002" blue="0.40000000000000002" alpha="1" colorSpace="calibratedRGB"/>
+                            <nil key="highlightedColor"/>
+                        </label>
+                        <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="coB-ye-PQ9">
+                            <rect key="frame" x="20" y="91" width="216" height="26"/>
+                            <constraints>
+                                <constraint firstAttribute="height" constant="26" id="WCB-bj-Xft"/>
+                            </constraints>
+                            <fontDescription key="fontDescription" type="system" pointSize="16"/>
+                            <color key="textColor" red="0.40000000000000002" green="0.40000000000000002" blue="0.40000000000000002" alpha="1" colorSpace="calibratedRGB"/>
+                            <nil key="highlightedColor"/>
+                        </label>
+                        <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="复制" textAlignment="right" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="vqA-fa-Tm9">
+                            <rect key="frame" x="241" y="91" width="34" height="26"/>
+                            <constraints>
+                                <constraint firstAttribute="height" constant="26" id="SOT-u3-oZy"/>
+                                <constraint firstAttribute="width" constant="34" id="Vup-ys-5h4"/>
+                            </constraints>
+                            <fontDescription key="fontDescription" type="system" pointSize="16"/>
+                            <color key="textColor" red="0.99607843137254903" green="0.14117647058823529" blue="0.31764705882352939" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+                            <nil key="highlightedColor"/>
+                        </label>
+                        <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="ddH-KT-ils">
+                            <rect key="frame" x="20" y="142" width="120" height="40"/>
+                            <constraints>
+                                <constraint firstAttribute="height" constant="40" id="X1a-5l-auk"/>
+                            </constraints>
+                            <fontDescription key="fontDescription" type="system" pointSize="16"/>
+                            <inset key="imageEdgeInsets" minX="0.0" minY="0.0" maxX="2.2250738585072014e-308" maxY="0.0"/>
+                            <state key="normal" title="取消">
+                                <color key="titleColor" red="0.20000000000000001" green="0.20000000000000001" blue="0.20000000000000001" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+                            </state>
+                            <userDefinedRuntimeAttributes>
+                                <userDefinedRuntimeAttribute type="number" keyPath="cornerRadius">
+                                    <real key="value" value="20"/>
+                                </userDefinedRuntimeAttribute>
+                                <userDefinedRuntimeAttribute type="number" keyPath="borderWidth">
+                                    <real key="value" value="1"/>
+                                </userDefinedRuntimeAttribute>
+                                <userDefinedRuntimeAttribute type="color" keyPath="borderColor">
+                                    <color key="value" red="0.85882352941176465" green="0.85882352941176465" blue="0.85882352941176465" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+                                </userDefinedRuntimeAttribute>
+                            </userDefinedRuntimeAttributes>
+                            <connections>
+                                <action selector="cancelAction:" destination="iN0-l3-epB" eventType="touchUpInside" id="ZSu-Gk-mpe"/>
+                            </connections>
+                        </button>
+                        <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="tz8-K5-sPv">
+                            <rect key="frame" x="155" y="142" width="120" height="40"/>
+                            <color key="backgroundColor" red="0.99607843137254903" green="0.14117647058823529" blue="0.31764705882352939" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+                            <fontDescription key="fontDescription" type="system" weight="medium" pointSize="16"/>
+                            <inset key="imageEdgeInsets" minX="0.0" minY="0.0" maxX="2.2250738585072014e-308" maxY="0.0"/>
+                            <state key="normal" title="打开文件"/>
+                            <userDefinedRuntimeAttributes>
+                                <userDefinedRuntimeAttribute type="number" keyPath="cornerRadius">
+                                    <real key="value" value="20"/>
+                                </userDefinedRuntimeAttribute>
+                            </userDefinedRuntimeAttributes>
+                            <connections>
+                                <action selector="sureAction:" destination="iN0-l3-epB" eventType="touchUpInside" id="8hA-Nj-c2w"/>
+                            </connections>
+                        </button>
+                        <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="Jmn-VN-WqG">
+                            <rect key="frame" x="238" y="84" width="40" height="40"/>
+                            <constraints>
+                                <constraint firstAttribute="height" constant="40" id="5gX-ME-Jg2"/>
+                                <constraint firstAttribute="width" constant="40" id="lub-j2-xqz"/>
+                            </constraints>
+                            <inset key="imageEdgeInsets" minX="0.0" minY="0.0" maxX="2.2250738585072014e-308" maxY="0.0"/>
+                            <connections>
+                                <action selector="copyActipn:" destination="iN0-l3-epB" eventType="touchUpInside" id="OoJ-tz-ppQ"/>
+                            </connections>
+                        </button>
+                    </subviews>
+                    <color key="backgroundColor" systemColor="systemBackgroundColor"/>
+                    <constraints>
+                        <constraint firstAttribute="width" constant="295" id="3eN-Q2-XWm"/>
+                        <constraint firstItem="tz8-K5-sPv" firstAttribute="height" secondItem="ddH-KT-ils" secondAttribute="height" id="3pM-TQ-xdm"/>
+                        <constraint firstItem="lnB-qu-Uf7" firstAttribute="top" secondItem="rhp-MD-4Jj" secondAttribute="top" constant="20" id="4GW-W9-UyJ"/>
+                        <constraint firstAttribute="trailing" secondItem="gVg-Vm-F6v" secondAttribute="trailing" id="5mh-6S-VBS"/>
+                        <constraint firstItem="vqA-fa-Tm9" firstAttribute="centerY" secondItem="coB-ye-PQ9" secondAttribute="centerY" id="6gf-ti-SgO"/>
+                        <constraint firstItem="gVg-Vm-F6v" firstAttribute="leading" secondItem="rhp-MD-4Jj" secondAttribute="leading" id="79Y-cy-LIl"/>
+                        <constraint firstItem="gVg-Vm-F6v" firstAttribute="top" secondItem="rhp-MD-4Jj" secondAttribute="top" id="8DV-gr-Qo9"/>
+                        <constraint firstItem="ddH-KT-ils" firstAttribute="leading" secondItem="rhp-MD-4Jj" secondAttribute="leading" constant="20" id="Bf6-Rk-qF4"/>
+                        <constraint firstAttribute="trailing" secondItem="vqA-fa-Tm9" secondAttribute="trailing" constant="20" id="Eqw-AM-TCV"/>
+                        <constraint firstItem="vqA-fa-Tm9" firstAttribute="centerX" secondItem="Jmn-VN-WqG" secondAttribute="centerX" id="HPp-JK-yOc"/>
+                        <constraint firstItem="tz8-K5-sPv" firstAttribute="leading" secondItem="ddH-KT-ils" secondAttribute="trailing" constant="15" id="Led-jk-T8L"/>
+                        <constraint firstItem="Pwc-SA-BPV" firstAttribute="centerY" secondItem="lnB-qu-Uf7" secondAttribute="centerY" id="Mcy-oo-gXb"/>
+                        <constraint firstAttribute="trailing" secondItem="Pwc-SA-BPV" secondAttribute="trailing" constant="20" id="Mzh-cE-g6X"/>
+                        <constraint firstItem="coB-ye-PQ9" firstAttribute="leading" secondItem="EP8-xw-on3" secondAttribute="leading" id="S8z-x4-lDg"/>
+                        <constraint firstAttribute="height" constant="202" id="VwM-cf-V34"/>
+                        <constraint firstItem="lnB-qu-Uf7" firstAttribute="centerX" secondItem="rhp-MD-4Jj" secondAttribute="centerX" id="Wbr-tA-eQK"/>
+                        <constraint firstItem="vqA-fa-Tm9" firstAttribute="leading" secondItem="coB-ye-PQ9" secondAttribute="trailing" constant="5" id="X0O-BV-Cms"/>
+                        <constraint firstItem="coB-ye-PQ9" firstAttribute="top" secondItem="EP8-xw-on3" secondAttribute="bottom" id="eeh-6H-wzh"/>
+                        <constraint firstAttribute="bottom" secondItem="ddH-KT-ils" secondAttribute="bottom" constant="20" id="eru-Yk-fPa"/>
+                        <constraint firstItem="vqA-fa-Tm9" firstAttribute="centerY" secondItem="Jmn-VN-WqG" secondAttribute="centerY" id="j3T-AK-nY6"/>
+                        <constraint firstAttribute="trailing" secondItem="XBP-di-P6K" secondAttribute="trailing" constant="10" id="kxs-yL-w5a"/>
+                        <constraint firstAttribute="trailing" secondItem="tz8-K5-sPv" secondAttribute="trailing" constant="20" id="oWS-db-HNt"/>
+                        <constraint firstAttribute="bottom" secondItem="tz8-K5-sPv" secondAttribute="bottom" constant="20" id="pMr-bZ-bxQ"/>
+                        <constraint firstItem="XBP-di-P6K" firstAttribute="top" secondItem="rhp-MD-4Jj" secondAttribute="top" constant="10" id="smj-VX-d6T"/>
+                        <constraint firstItem="EP8-xw-on3" firstAttribute="leading" secondItem="rhp-MD-4Jj" secondAttribute="leading" constant="20" id="xcN-36-gGR"/>
+                        <constraint firstItem="tz8-K5-sPv" firstAttribute="width" secondItem="ddH-KT-ils" secondAttribute="width" id="xho-Dp-FwO"/>
+                        <constraint firstItem="EP8-xw-on3" firstAttribute="top" secondItem="lnB-qu-Uf7" secondAttribute="bottom" constant="20" id="xkt-Ro-jr6"/>
+                    </constraints>
+                    <userDefinedRuntimeAttributes>
+                        <userDefinedRuntimeAttribute type="number" keyPath="cornerRadius">
+                            <real key="value" value="20"/>
+                        </userDefinedRuntimeAttribute>
+                    </userDefinedRuntimeAttributes>
+                </view>
+            </subviews>
+            <color key="backgroundColor" red="0.0" green="0.0" blue="0.0" alpha="0.59999999999999998" colorSpace="custom" customColorSpace="sRGB"/>
+            <gestureRecognizers/>
+            <constraints>
+                <constraint firstItem="rhp-MD-4Jj" firstAttribute="centerX" secondItem="iN0-l3-epB" secondAttribute="centerX" id="IFT-nf-SXW"/>
+                <constraint firstItem="rhp-MD-4Jj" firstAttribute="centerY" secondItem="iN0-l3-epB" secondAttribute="centerY" id="JhP-yi-vvP"/>
+            </constraints>
+            <nil key="simulatedTopBarMetrics"/>
+            <nil key="simulatedBottomBarMetrics"/>
+            <freeformSimulatedSizeMetrics key="simulatedDestinationMetrics"/>
+            <connections>
+                <outlet property="containerView" destination="rhp-MD-4Jj" id="CRJ-w6-5Iw"/>
+                <outlet property="descLabel" destination="coB-ye-PQ9" id="qkh-H7-5Vc"/>
+            </connections>
+            <point key="canvasLocation" x="35.877862595419849" y="19.718309859154932"/>
+        </view>
+    </objects>
+    <resources>
+        <image name="check_cancle" width="14" height="14"/>
+        <image name="download_topLayer" width="295" height="49"/>
+        <systemColor name="systemBackgroundColor">
+            <color white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
+        </systemColor>
+    </resources>
+</document>

+ 1 - 1
KulexiuForStudent/Pods/Pods.xcodeproj/xcuserdata/wangzhi.xcuserdatad/xcschemes/AFNetworking.xcscheme

@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <Scheme
-   LastUpgradeVersion = "1530"
+   LastUpgradeVersion = "1540"
    version = "1.3">
    <BuildAction
       parallelizeBuildables = "YES"

+ 1 - 1
KulexiuForStudent/Pods/Pods.xcodeproj/xcuserdata/wangzhi.xcuserdatad/xcschemes/Bugly.xcscheme

@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <Scheme
-   LastUpgradeVersion = "1530"
+   LastUpgradeVersion = "1540"
    version = "1.3">
    <BuildAction
       parallelizeBuildables = "YES"

+ 1 - 1
KulexiuForStudent/Pods/Pods.xcodeproj/xcuserdata/wangzhi.xcuserdatad/xcschemes/CHIPageControl.xcscheme

@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <Scheme
-   LastUpgradeVersion = "1530"
+   LastUpgradeVersion = "1540"
    version = "1.3">
    <BuildAction
       parallelizeBuildables = "YES"

+ 1 - 1
KulexiuForStudent/Pods/Pods.xcodeproj/xcuserdata/wangzhi.xcuserdatad/xcschemes/IQKeyboardManager.xcscheme

@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <Scheme
-   LastUpgradeVersion = "1530"
+   LastUpgradeVersion = "1540"
    version = "1.3">
    <BuildAction
       parallelizeBuildables = "YES"

+ 1 - 1
KulexiuForStudent/Pods/Pods.xcodeproj/xcuserdata/wangzhi.xcuserdatad/xcschemes/JCore.xcscheme

@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <Scheme
-   LastUpgradeVersion = "1530"
+   LastUpgradeVersion = "1540"
    version = "1.3">
    <BuildAction
       parallelizeBuildables = "YES"

+ 1 - 1
KulexiuForStudent/Pods/Pods.xcodeproj/xcuserdata/wangzhi.xcuserdatad/xcschemes/JPush.xcscheme

@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <Scheme
-   LastUpgradeVersion = "1530"
+   LastUpgradeVersion = "1540"
    version = "1.3">
    <BuildAction
       parallelizeBuildables = "YES"

+ 1 - 1
KulexiuForStudent/Pods/Pods.xcodeproj/xcuserdata/wangzhi.xcuserdatad/xcschemes/JXCategoryView.xcscheme

@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <Scheme
-   LastUpgradeVersion = "1530"
+   LastUpgradeVersion = "1540"
    version = "1.3">
    <BuildAction
       parallelizeBuildables = "YES"

+ 1 - 1
KulexiuForStudent/Pods/Pods.xcodeproj/xcuserdata/wangzhi.xcuserdatad/xcschemes/JXPagingView.xcscheme

@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <Scheme
-   LastUpgradeVersion = "1530"
+   LastUpgradeVersion = "1540"
    version = "1.3">
    <BuildAction
       parallelizeBuildables = "YES"

+ 1 - 1
KulexiuForStudent/Pods/Pods.xcodeproj/xcuserdata/wangzhi.xcuserdatad/xcschemes/MBProgressHUD.xcscheme

@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <Scheme
-   LastUpgradeVersion = "1530"
+   LastUpgradeVersion = "1540"
    version = "1.3">
    <BuildAction
       parallelizeBuildables = "YES"

+ 1 - 1
KulexiuForStudent/Pods/Pods.xcodeproj/xcuserdata/wangzhi.xcuserdatad/xcschemes/MJExtension.xcscheme

@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <Scheme
-   LastUpgradeVersion = "1530"
+   LastUpgradeVersion = "1540"
    version = "1.3">
    <BuildAction
       parallelizeBuildables = "YES"

+ 1 - 1
KulexiuForStudent/Pods/Pods.xcodeproj/xcuserdata/wangzhi.xcuserdatad/xcschemes/MJRefresh.xcscheme

@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <Scheme
-   LastUpgradeVersion = "1530"
+   LastUpgradeVersion = "1540"
    version = "1.3">
    <BuildAction
       parallelizeBuildables = "YES"

+ 1 - 1
KulexiuForStudent/Pods/Pods.xcodeproj/xcuserdata/wangzhi.xcuserdatad/xcschemes/Masonry.xcscheme

@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <Scheme
-   LastUpgradeVersion = "1530"
+   LastUpgradeVersion = "1540"
    version = "1.3">
    <BuildAction
       parallelizeBuildables = "YES"

+ 1 - 1
KulexiuForStudent/Pods/Pods.xcodeproj/xcuserdata/wangzhi.xcuserdatad/xcschemes/Pods-KulexiuForStudent-KulexiuForStudentUITests.xcscheme

@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <Scheme
-   LastUpgradeVersion = "1530"
+   LastUpgradeVersion = "1540"
    version = "1.3">
    <BuildAction
       parallelizeBuildables = "YES"

+ 1 - 1
KulexiuForStudent/Pods/Pods.xcodeproj/xcuserdata/wangzhi.xcuserdatad/xcschemes/Pods-KulexiuForStudent.xcscheme

@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <Scheme
-   LastUpgradeVersion = "1530"
+   LastUpgradeVersion = "1540"
    version = "1.3">
    <BuildAction
       parallelizeBuildables = "YES"

+ 1 - 1
KulexiuForStudent/Pods/Pods.xcodeproj/xcuserdata/wangzhi.xcuserdatad/xcschemes/Pods-KulexiuForStudentTests.xcscheme

@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <Scheme
-   LastUpgradeVersion = "1530"
+   LastUpgradeVersion = "1540"
    version = "1.3">
    <BuildAction
       parallelizeBuildables = "YES"

+ 1 - 1
KulexiuForStudent/Pods/Pods.xcodeproj/xcuserdata/wangzhi.xcuserdatad/xcschemes/RSKImageCropper.xcscheme

@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <Scheme
-   LastUpgradeVersion = "1530"
+   LastUpgradeVersion = "1540"
    version = "1.3">
    <BuildAction
       parallelizeBuildables = "YES"

+ 1 - 1
KulexiuForStudent/Pods/Pods.xcodeproj/xcuserdata/wangzhi.xcuserdatad/xcschemes/Reachability.xcscheme

@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <Scheme
-   LastUpgradeVersion = "1530"
+   LastUpgradeVersion = "1540"
    version = "1.3">
    <BuildAction
       parallelizeBuildables = "YES"

+ 1 - 1
KulexiuForStudent/Pods/Pods.xcodeproj/xcuserdata/wangzhi.xcuserdatad/xcschemes/SDWebImage.xcscheme

@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <Scheme
-   LastUpgradeVersion = "1530"
+   LastUpgradeVersion = "1540"
    version = "1.3">
    <BuildAction
       parallelizeBuildables = "YES"

+ 1 - 1
KulexiuForStudent/Pods/Pods.xcodeproj/xcuserdata/wangzhi.xcuserdatad/xcschemes/SSZipArchive.xcscheme

@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <Scheme
-   LastUpgradeVersion = "1530"
+   LastUpgradeVersion = "1540"
    version = "1.3">
    <BuildAction
       parallelizeBuildables = "YES"

+ 1 - 1
KulexiuForStudent/Pods/Pods.xcodeproj/xcuserdata/wangzhi.xcuserdatad/xcschemes/SocketRocket.xcscheme

@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <Scheme
-   LastUpgradeVersion = "1530"
+   LastUpgradeVersion = "1540"
    version = "1.3">
    <BuildAction
       parallelizeBuildables = "YES"

+ 1 - 1
KulexiuForStudent/Pods/Pods.xcodeproj/xcuserdata/wangzhi.xcuserdatad/xcschemes/Whiteboard-Whiteboard.xcscheme

@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <Scheme
-   LastUpgradeVersion = "1530"
+   LastUpgradeVersion = "1540"
    version = "1.3">
    <BuildAction
       parallelizeBuildables = "YES"

+ 1 - 1
KulexiuForStudent/Pods/Pods.xcodeproj/xcuserdata/wangzhi.xcuserdatad/xcschemes/Whiteboard.xcscheme

@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <Scheme
-   LastUpgradeVersion = "1530"
+   LastUpgradeVersion = "1540"
    version = "1.3">
    <BuildAction
       parallelizeBuildables = "YES"

+ 1 - 1
KulexiuForStudent/Pods/Pods.xcodeproj/xcuserdata/wangzhi.xcuserdatad/xcschemes/YYModel.xcscheme

@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <Scheme
-   LastUpgradeVersion = "1530"
+   LastUpgradeVersion = "1540"
    version = "1.3">
    <BuildAction
       parallelizeBuildables = "YES"