Procházet zdrojové kódy

1.修改iOS Apex Driver完成离线数据读取。

Pen Li před 7 roky
rodič
revize
3339e93636

+ 20 - 0
Redant Drivers/Apex And Drivers.xcodeproj/project.pbxproj

@@ -37,6 +37,7 @@
 		420D112B2133F98600149B37 /* fake_order_filter.json in Resources */ = {isa = PBXBuildFile; fileRef = 420D112A2133F98600149B37 /* fake_order_filter.json */; };
 		420D112B2133F98600149B37 /* fake_order_filter.json in Resources */ = {isa = PBXBuildFile; fileRef = 420D112A2133F98600149B37 /* fake_order_filter.json */; };
 		421C417621719EB500835447 /* RALoginNavigationController.m in Sources */ = {isa = PBXBuildFile; fileRef = 421C417521719EB500835447 /* RALoginNavigationController.m */; };
 		421C417621719EB500835447 /* RALoginNavigationController.m in Sources */ = {isa = PBXBuildFile; fileRef = 421C417521719EB500835447 /* RALoginNavigationController.m */; };
 		421C417921719F8100835447 /* RALoginBackgroundView.m in Sources */ = {isa = PBXBuildFile; fileRef = 421C417821719F8100835447 /* RALoginBackgroundView.m */; };
 		421C417921719F8100835447 /* RALoginBackgroundView.m in Sources */ = {isa = PBXBuildFile; fileRef = 421C417821719F8100835447 /* RALoginBackgroundView.m */; };
+		421C43ED217EEF0600D80B82 /* RAReachability.m in Sources */ = {isa = PBXBuildFile; fileRef = 421C43EC217EEF0600D80B82 /* RAReachability.m */; };
 		422B06BC21743ABE003DA2DA /* NSData+RAImageType.m in Sources */ = {isa = PBXBuildFile; fileRef = 422B06BB21743ABE003DA2DA /* NSData+RAImageType.m */; };
 		422B06BC21743ABE003DA2DA /* NSData+RAImageType.m in Sources */ = {isa = PBXBuildFile; fileRef = 422B06BB21743ABE003DA2DA /* NSData+RAImageType.m */; };
 		422BD95C213CE0F300DF8E89 /* HomeHeader.xib in Resources */ = {isa = PBXBuildFile; fileRef = 422BD95B213CE0F300DF8E89 /* HomeHeader.xib */; };
 		422BD95C213CE0F300DF8E89 /* HomeHeader.xib in Resources */ = {isa = PBXBuildFile; fileRef = 422BD95B213CE0F300DF8E89 /* HomeHeader.xib */; };
 		422BD95F213CE2E600DF8E89 /* RABadgeNumberView.m in Sources */ = {isa = PBXBuildFile; fileRef = 422BD95E213CE2E600DF8E89 /* RABadgeNumberView.m */; };
 		422BD95F213CE2E600DF8E89 /* RABadgeNumberView.m in Sources */ = {isa = PBXBuildFile; fileRef = 422BD95E213CE2E600DF8E89 /* RABadgeNumberView.m */; };
@@ -130,6 +131,7 @@
 		4281100320E4D47000315156 /* JLRefreshBasis.m in Sources */ = {isa = PBXBuildFile; fileRef = 42810FFC20E4D46F00315156 /* JLRefreshBasis.m */; };
 		4281100320E4D47000315156 /* JLRefreshBasis.m in Sources */ = {isa = PBXBuildFile; fileRef = 42810FFC20E4D46F00315156 /* JLRefreshBasis.m */; };
 		4281100420E4D47000315156 /* UIScrollView+JLRefresh.m in Sources */ = {isa = PBXBuildFile; fileRef = 42810FFE20E4D46F00315156 /* UIScrollView+JLRefresh.m */; };
 		4281100420E4D47000315156 /* UIScrollView+JLRefresh.m in Sources */ = {isa = PBXBuildFile; fileRef = 42810FFE20E4D46F00315156 /* UIScrollView+JLRefresh.m */; };
 		4281100520E4D47000315156 /* UIView+JLExtension.m in Sources */ = {isa = PBXBuildFile; fileRef = 4281100020E4D46F00315156 /* UIView+JLExtension.m */; };
 		4281100520E4D47000315156 /* UIView+JLExtension.m in Sources */ = {isa = PBXBuildFile; fileRef = 4281100020E4D46F00315156 /* UIView+JLExtension.m */; };
+		4282B5B6217DB219001EBCE2 /* RAOfflineHandler.m in Sources */ = {isa = PBXBuildFile; fileRef = 4282B5B5217DB219001EBCE2 /* RAOfflineHandler.m */; };
 		429A0AD7216CA666004DEF7A /* RASettingLinkCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 429A0AD6216CA666004DEF7A /* RASettingLinkCell.m */; };
 		429A0AD7216CA666004DEF7A /* RASettingLinkCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 429A0AD6216CA666004DEF7A /* RASettingLinkCell.m */; };
 		429A0ADA216CA6A6004DEF7A /* RASettingLinkModel.m in Sources */ = {isa = PBXBuildFile; fileRef = 429A0AD9216CA6A6004DEF7A /* RASettingLinkModel.m */; };
 		429A0ADA216CA6A6004DEF7A /* RASettingLinkModel.m in Sources */ = {isa = PBXBuildFile; fileRef = 429A0AD9216CA6A6004DEF7A /* RASettingLinkModel.m */; };
 		429CF61C20E0E32E00CE8DAD /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = 429CF61E20E0E32E00CE8DAD /* Localizable.strings */; };
 		429CF61C20E0E32E00CE8DAD /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = 429CF61E20E0E32E00CE8DAD /* Localizable.strings */; };
@@ -249,6 +251,8 @@
 		421C417521719EB500835447 /* RALoginNavigationController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = RALoginNavigationController.m; sourceTree = "<group>"; };
 		421C417521719EB500835447 /* RALoginNavigationController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = RALoginNavigationController.m; sourceTree = "<group>"; };
 		421C417721719F8100835447 /* RALoginBackgroundView.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RALoginBackgroundView.h; sourceTree = "<group>"; };
 		421C417721719F8100835447 /* RALoginBackgroundView.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RALoginBackgroundView.h; sourceTree = "<group>"; };
 		421C417821719F8100835447 /* RALoginBackgroundView.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = RALoginBackgroundView.m; sourceTree = "<group>"; };
 		421C417821719F8100835447 /* RALoginBackgroundView.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = RALoginBackgroundView.m; sourceTree = "<group>"; };
+		421C43EB217EEF0600D80B82 /* RAReachability.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = RAReachability.h; path = ../../common/RAReachability.h; sourceTree = "<group>"; };
+		421C43EC217EEF0600D80B82 /* RAReachability.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; name = RAReachability.m; path = ../../common/RAReachability.m; sourceTree = "<group>"; };
 		422B06BA21743ABE003DA2DA /* NSData+RAImageType.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "NSData+RAImageType.h"; sourceTree = "<group>"; };
 		422B06BA21743ABE003DA2DA /* NSData+RAImageType.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "NSData+RAImageType.h"; sourceTree = "<group>"; };
 		422B06BB21743ABE003DA2DA /* NSData+RAImageType.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = "NSData+RAImageType.m"; sourceTree = "<group>"; };
 		422B06BB21743ABE003DA2DA /* NSData+RAImageType.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = "NSData+RAImageType.m"; sourceTree = "<group>"; };
 		422BD95B213CE0F300DF8E89 /* HomeHeader.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = HomeHeader.xib; sourceTree = "<group>"; };
 		422BD95B213CE0F300DF8E89 /* HomeHeader.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = HomeHeader.xib; sourceTree = "<group>"; };
@@ -428,6 +432,8 @@
 		42810FFE20E4D46F00315156 /* UIScrollView+JLRefresh.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UIScrollView+JLRefresh.m"; sourceTree = "<group>"; };
 		42810FFE20E4D46F00315156 /* UIScrollView+JLRefresh.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UIScrollView+JLRefresh.m"; sourceTree = "<group>"; };
 		42810FFF20E4D46F00315156 /* UIView+JLExtension.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UIView+JLExtension.h"; sourceTree = "<group>"; };
 		42810FFF20E4D46F00315156 /* UIView+JLExtension.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UIView+JLExtension.h"; sourceTree = "<group>"; };
 		4281100020E4D46F00315156 /* UIView+JLExtension.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UIView+JLExtension.m"; sourceTree = "<group>"; };
 		4281100020E4D46F00315156 /* UIView+JLExtension.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UIView+JLExtension.m"; sourceTree = "<group>"; };
+		4282B5B4217DB219001EBCE2 /* RAOfflineHandler.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RAOfflineHandler.h; sourceTree = "<group>"; };
+		4282B5B5217DB219001EBCE2 /* RAOfflineHandler.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = RAOfflineHandler.m; sourceTree = "<group>"; };
 		429A0AD5216CA666004DEF7A /* RASettingLinkCell.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RASettingLinkCell.h; sourceTree = "<group>"; };
 		429A0AD5216CA666004DEF7A /* RASettingLinkCell.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RASettingLinkCell.h; sourceTree = "<group>"; };
 		429A0AD6216CA666004DEF7A /* RASettingLinkCell.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = RASettingLinkCell.m; sourceTree = "<group>"; };
 		429A0AD6216CA666004DEF7A /* RASettingLinkCell.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = RASettingLinkCell.m; sourceTree = "<group>"; };
 		429A0AD8216CA6A6004DEF7A /* RASettingLinkModel.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RASettingLinkModel.h; sourceTree = "<group>"; };
 		429A0AD8216CA6A6004DEF7A /* RASettingLinkModel.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RASettingLinkModel.h; sourceTree = "<group>"; };
@@ -727,6 +733,8 @@
 				42529D3F20C0EA59000C0F4D /* Reachability.m */,
 				42529D3F20C0EA59000C0F4D /* Reachability.m */,
 				42529D1F20C0E8EB000C0F4D /* NetworkUtils.h */,
 				42529D1F20C0E8EB000C0F4D /* NetworkUtils.h */,
 				42529D2020C0E8EC000C0F4D /* NetworkUtils.m */,
 				42529D2020C0E8EC000C0F4D /* NetworkUtils.m */,
+				421C43EB217EEF0600D80B82 /* RAReachability.h */,
+				421C43EC217EEF0600D80B82 /* RAReachability.m */,
 			);
 			);
 			name = Network;
 			name = Network;
 			sourceTree = "<group>";
 			sourceTree = "<group>";
@@ -992,6 +1000,15 @@
 			path = Header;
 			path = Header;
 			sourceTree = "<group>";
 			sourceTree = "<group>";
 		};
 		};
+		4282B5B3217DB1F3001EBCE2 /* Offline */ = {
+			isa = PBXGroup;
+			children = (
+				4282B5B4217DB219001EBCE2 /* RAOfflineHandler.h */,
+				4282B5B5217DB219001EBCE2 /* RAOfflineHandler.m */,
+			);
+			path = Offline;
+			sourceTree = "<group>";
+		};
 		42C1B2712134F23000637085 /* DatePicker */ = {
 		42C1B2712134F23000637085 /* DatePicker */ = {
 			isa = PBXGroup;
 			isa = PBXGroup;
 			children = (
 			children = (
@@ -1261,6 +1278,7 @@
 				424204EB20C66CFE005AEED9 /* PhotoPreView */,
 				424204EB20C66CFE005AEED9 /* PhotoPreView */,
 				425B97D220C7B7E100B35713 /* Upload */,
 				425B97D220C7B7E100B35713 /* Upload */,
 				4235FAA4213E24FE000B6672 /* Signature */,
 				4235FAA4213E24FE000B6672 /* Signature */,
+				4282B5B3217DB1F3001EBCE2 /* Offline */,
 				425B97C920C7895F00B35713 /* RASingleton.h */,
 				425B97C920C7895F00B35713 /* RASingleton.h */,
 				425B97CA20C7895F00B35713 /* RASingleton.m */,
 				425B97CA20C7895F00B35713 /* RASingleton.m */,
 				423C6A4C20C909FC00455E27 /* RANotificationNameCenter.h */,
 				423C6A4C20C909FC00455E27 /* RANotificationNameCenter.h */,
@@ -1413,6 +1431,7 @@
 				42D8B8CF20C2657D001C125F /* RADetailBaseModel.m in Sources */,
 				42D8B8CF20C2657D001C125F /* RADetailBaseModel.m in Sources */,
 				4259598F2148FD9200F7DD41 /* RASettingViewController+TableDelegate.m in Sources */,
 				4259598F2148FD9200F7DD41 /* RASettingViewController+TableDelegate.m in Sources */,
 				42F0C5D720E20B3F00922442 /* RACameraViewController.m in Sources */,
 				42F0C5D720E20B3F00922442 /* RACameraViewController.m in Sources */,
+				4282B5B6217DB219001EBCE2 /* RAOfflineHandler.m in Sources */,
 				4205FD5520C0F50C00DB42B4 /* JLPresentationController.m in Sources */,
 				4205FD5520C0F50C00DB42B4 /* JLPresentationController.m in Sources */,
 				424204EE20C66D20005AEED9 /* RAPhotoPreviewController.m in Sources */,
 				424204EE20C66D20005AEED9 /* RAPhotoPreviewController.m in Sources */,
 				42529D3D20C0EA3F000C0F4D /* ZipArchive.mm in Sources */,
 				42529D3D20C0EA3F000C0F4D /* ZipArchive.mm in Sources */,
@@ -1476,6 +1495,7 @@
 				424204DC20C61561005AEED9 /* RAQRCodeScannerViewController.m in Sources */,
 				424204DC20C61561005AEED9 /* RAQRCodeScannerViewController.m in Sources */,
 				42D8B8D520C27399001C125F /* RADetailActionsCell+CollectionViewDelegate.m in Sources */,
 				42D8B8D520C27399001C125F /* RADetailActionsCell+CollectionViewDelegate.m in Sources */,
 				424204E720C668AE005AEED9 /* RATakePhotoPreviewController.m in Sources */,
 				424204E720C668AE005AEED9 /* RATakePhotoPreviewController.m in Sources */,
+				421C43ED217EEF0600D80B82 /* RAReachability.m in Sources */,
 				42C6074C21536E5A003E5379 /* RAExceptionHandler.m in Sources */,
 				42C6074C21536E5A003E5379 /* RAExceptionHandler.m in Sources */,
 				42810FEE20E4C93400315156 /* RAHomeMoreViewController+TableDataSource.m in Sources */,
 				42810FEE20E4C93400315156 /* RAHomeMoreViewController+TableDataSource.m in Sources */,
 				4205FD6C20C13E0700DB42B4 /* RAHomeViewController+HomeTableDelegate.m in Sources */,
 				4205FD6C20C13E0700DB42B4 /* RAHomeViewController+HomeTableDelegate.m in Sources */,

+ 8 - 0
Redant Drivers/Apex And Drivers/AppDelegate.m

@@ -13,6 +13,7 @@
 #import "RANavigationController.h"
 #import "RANavigationController.h"
 #import "RAExceptionHandler.h"
 #import "RAExceptionHandler.h"
 #import "RALoginNavigationController.h"
 #import "RALoginNavigationController.h"
+#import "RAReachability.h"
 
 
 @interface AppDelegate ()<UNUserNotificationCenterDelegate,CLLocationManagerDelegate>
 @interface AppDelegate ()<UNUserNotificationCenterDelegate,CLLocationManagerDelegate>
 
 
@@ -134,6 +135,13 @@
     }];
     }];
     // 禁止Disk缓存,否则会和程序实现的缓存重复
     // 禁止Disk缓存,否则会和程序实现的缓存重复
     [[NSURLCache sharedURLCache] setDiskCapacity:0];
     [[NSURLCache sharedURLCache] setDiskCapacity:0];
+
+#ifdef OFFLINE_MODE
+    [[RAReachability defaultReachability] startNotifier:^(BOOL reachable) {
+        
+        [RASingleton sharedInstance].offline = !reachable;
+    }];
+#endif
     
     
     // View
     // View
     
     

+ 2 - 0
Redant Drivers/Apex And Drivers/Detail/Model/Collection/RADetailActionModel.h

@@ -35,6 +35,8 @@ typedef enum {
 @property (nonatomic,assign) RADetailActionSubType actionSubType;
 @property (nonatomic,assign) RADetailActionSubType actionSubType;
 @property (nonatomic,copy) NSString *actionTitle;
 @property (nonatomic,copy) NSString *actionTitle;
 
 
+@property (nonatomic,assign) NSInteger index;///< offline添加,用于判断action的顺序
+
 #pragma mark - actionType == RADetailActionTypeRemote
 #pragma mark - actionType == RADetailActionTypeRemote
 
 
 @property (nonatomic,copy) NSString *url;///<
 @property (nonatomic,copy) NSString *url;///<

+ 1 - 0
Redant Drivers/Apex And Drivers/Detail/RAOrderDetailViewController+TableViewDataSource.m

@@ -349,6 +349,7 @@
     vc.title = model.actionTitle;
     vc.title = model.actionTitle;
     vc.orderID = self.orderID;
     vc.orderID = self.orderID;
     vc.actionID = model.actionID;
     vc.actionID = model.actionID;
+    vc.actionIdx = model.index;
     vc.actionTitle = model.actionTitle;
     vc.actionTitle = model.actionTitle;
     vc.orderType2 = self.orderType2;
     vc.orderType2 = self.orderType2;
     [self.navigationController pushViewController:vc animated:YES];
     [self.navigationController pushViewController:vc animated:YES];

+ 62 - 0
Redant Drivers/Apex And Drivers/Offline/RAOfflineHandler.h

@@ -0,0 +1,62 @@
+//
+//  RAOfflineHandler.h
+//  Apex And Drivers
+//
+//  Created by Jack on 2018/10/22.
+//  Copyright © 2018年 USAI. All rights reserved.
+//
+
+#import <Foundation/Foundation.h>
+
+NS_ASSUME_NONNULL_BEGIN
+
+@interface RAOfflineHandler : NSObject
+
+/**
+ * @brief 使用OfflineHandler,通过此方法获取
+ */
++ (instancetype)defaultHandler;
+
+/**
+ * @brief 向服务器请求离线数据
+ */
+- (void)downloadOfflineData;
+
+/**
+ * @brief 加载离线首页数据
+ */
+- (NSDictionary *)requestOfflineHome;
+
+/**
+ * @brief 加载离线Detail
+ * @param orderId 订单号
+ * @param type 订单类型,包括 new order 和 processing order
+ * @return order detail界面数据
+ */
+- (NSDictionary *)requestOfflineDetailForOrder:(NSString *)orderId withOrderType:(NSInteger)type;
+
+/**
+ * @brief 在detail中过滤订单已经做过的操作
+ * @param detail order detail界面数据
+ * @param finish order最后完成的一个action索引
+ * @return 最后过滤后的detail
+ */
+- (NSMutableDictionary *)filtrateActionFromDetail:(NSMutableDictionary *)detail withFinishActions:(NSNumber *)finish;
+
+/**
+ * @brief 记载离线Edit Order
+ * @param orderId 订单号
+ * @param actionIndex 操作索引
+ */
+- (NSDictionary *)requestOfflineEditOrder:(NSString *)orderId withAction:(NSInteger)actionIndex;
+
+/**
+ * @brief 最后一次修改Order的 Action 索引
+ * @param orderId 订单号
+ * @return 最后一次修改order的action索引
+ */
+- (NSNumber *)lastActionIndexForOrder:(NSString *)orderId;
+
+@end
+
+NS_ASSUME_NONNULL_END

+ 342 - 0
Redant Drivers/Apex And Drivers/Offline/RAOfflineHandler.m

@@ -0,0 +1,342 @@
+//
+//  RAOfflineHandler.m
+//  Apex And Drivers
+//
+//  Created by Jack on 2018/10/22.
+//  Copyright © 2018年 USAI. All rights reserved.
+//
+
+#import "RAOfflineHandler.h"
+#import "NetworkUtils.h"
+#import "ZipArchive.h"
+#import "RADetailBaseModel.h"
+
+#define Lock() dispatch_semaphore_wait(_lock, DISPATCH_TIME_FOREVER)
+#define Unlock() dispatch_semaphore_signal(_lock)
+
+static dispatch_semaphore_t _lock;
+
+@interface RAOfflineHandler () {
+    NSString *_offlineDir;
+    NSString *_offlineTmp;
+}
+
+@property (nonatomic,strong) NSMutableDictionary *detailCache;///< 缓存查看过的Detai
+@property (nonatomic,strong,readonly) NSString *offlineDir; ///< 缓存文件夹
+@property (nonatomic,strong,readonly) NSString *offlineTmp; ///< 临时保存解压文件的文件夹
+
+@end
+
+@implementation RAOfflineHandler
+
++ (instancetype)defaultHandler {
+    static RAOfflineHandler *handler;
+    static dispatch_once_t token;
+    dispatch_once(&token, ^{
+        handler = [[RAOfflineHandler alloc] init];
+        _lock = dispatch_semaphore_create(1);
+    });
+    return handler;
+}
+
+- (NSString *)offlineDir {
+    if (!_offlineDir) {
+        
+        NSString *cachePath = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject];
+        _offlineDir = [cachePath stringByAppendingPathComponent:@"offline"];
+        
+        NSFileManager *fm = [NSFileManager defaultManager];
+        BOOL isDir = YES;
+        if ([fm fileExistsAtPath:_offlineDir isDirectory:&isDir] && isDir) {
+            
+        } else {
+            [fm createDirectoryAtPath:_offlineDir withIntermediateDirectories:NO attributes:nil error:nil];
+        }
+        
+    }
+    return _offlineDir;
+    
+}
+
+- (NSString *)offlineTmp {
+    if (!_offlineTmp) {
+        
+        _offlineTmp = [self.offlineDir stringByAppendingPathComponent:@"tmp"];
+        
+        NSFileManager *fm = [NSFileManager defaultManager];
+        BOOL isDir = YES;
+        if ([fm fileExistsAtPath:_offlineDir isDirectory:&isDir] && isDir) {
+            
+        } else {
+            [fm createDirectoryAtPath:_offlineDir withIntermediateDirectories:NO attributes:nil error:nil];
+        }
+    }
+    return _offlineTmp;
+}
+
+/**
+ * @brief 向服务器请求离线数据
+ */
+- (void)downloadOfflineData {
+    
+    dispatch_async(dispatch_get_global_queue(0, 0), ^{
+       
+        NSMutableDictionary *params = [NSMutableDictionary dictionary];
+        [NetworkUtils downloadFileOffset:0 Param:params from:@"" method:@"POST" toPath:self.offlineDir progressHandler:^(NSURLSessionTask *task, double progress) {
+            
+        } completionHandler:^(NSMutableDictionary *result) {
+           
+            int rs = [[result objectForKey:@"result"] intValue];
+            NSString *path = [result objectForKey:@"path"];
+            if (rs == RESULT_TRUE) {
+                [self handleDownloadFile:path];
+            }
+            
+        }];
+        
+    });
+}
+
+/**
+ * @brief 加载沙盒中的数据
+ * @param path 沙盒数据路径
+ */
+- (NSDictionary *)_loadCacheData:(NSString *)path {
+    if (path == nil || path.length == 0) {
+        return nil;
+    }
+    
+    NSData *data = [NSData dataWithContentsOfFile:path];
+    NSDictionary *dic = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableContainers error:nil];
+    return dic;
+}
+
+/**
+ * @brief 处理下载的压缩文件
+ * @param path 压缩文件路径
+ */
+- (void)handleDownloadFile:(NSString *)path {
+    
+    Lock();
+    
+    // 解压
+    BOOL zipRes = [self _unzipOfflineZip:path toDir:self.offlineTmp];
+    if (zipRes) {
+        NSFileManager *fm = [NSFileManager defaultManager];
+        
+        // 删除旧数据,除了tmp
+        NSArray<NSString *> *items = [fm contentsOfDirectoryAtPath:self.offlineDir error:nil];
+        [items enumerateObjectsUsingBlock:^(NSString * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
+            if (![obj isEqualToString:self.offlineTmp]) {
+                [fm removeItemAtPath:obj error:nil];
+            }
+        }];
+        
+        // 将tmp中解压数据移出来
+        items = [fm contentsOfDirectoryAtPath:self.offlineTmp error:nil];
+        [items enumerateObjectsUsingBlock:^(NSString * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
+            
+            NSString *lastComponent = [obj lastPathComponent];
+            NSString *to = [self.offlineDir stringByAppendingPathComponent:lastComponent];
+            [fm moveItemAtPath:obj toPath:to error:nil];
+        }];
+        
+        // 重置缓存的action
+        [self _resetFinish];
+    }
+    
+    Unlock();
+}
+
+/**
+ * @brief 解压离线下载的压缩包
+ * @return 解压是否成功
+ */
+- (BOOL)_unzipOfflineZip:(NSString *)path toDir:(NSString *)to {
+    
+    ZipArchive* zip = [[ZipArchive alloc] init];
+    BOOL zipRes = [zip UnzipOpenFile:path Password:@""];
+    if (zipRes) {
+        zipRes = [zip UnzipFileTo:to overWrite:YES];
+    }
+    
+    return zipRes;
+}
+
+/**
+ * @brief 重置离线完成的Action,将finished order对应的action的剔除
+ */
+- (void)_resetFinish {
+    
+    NSDictionary *homeJson = [self _requestOfflineHome];
+    NSArray<NSDictionary *> *sections = [homeJson objectForKey:@"sections"];
+    
+    NSMutableDictionary *finishDic = [NSMutableDictionary dictionary];
+    NSDictionary *finishDicTmp = [self _finishedActions];
+    if (finishDicTmp.count > 0) {
+        [sections enumerateObjectsUsingBlock:^(NSDictionary *  _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
+            
+            NSArray<NSDictionary *> *orders = [obj objectForKey:@"orders"];
+            [orders enumerateObjectsUsingBlock:^(NSDictionary *  _Nonnull order, NSUInteger idx, BOOL * _Nonnull stop) {
+                
+                NSString *orderId = [order objectForKey:@"orderID"];
+                NSNumber *finish = [finishDicTmp objectForKey:orderId];
+                if (finish) {
+                    [finishDic setObject:finish forKey:orderId];
+                }
+            }];
+        }];
+    }
+    
+    NSString *finishPath = [self.offlineDir stringByAppendingPathComponent:@"finish"];
+    [finishDic writeToFile:finishPath atomically:NO];
+}
+
+/**
+ * @brief 加载所有完成的订单Action
+ */
+- (NSDictionary<NSString *, NSNumber *> *)_finishedActions {
+    
+    NSString *path = [self.offlineDir stringByAppendingPathComponent:@"finish"];
+    NSDictionary *dic = [NSDictionary dictionaryWithContentsOfFile:path];
+    
+    return dic;
+}
+
+/**
+ * @brief 加载离线首页数据
+ */
+- (NSDictionary *)_requestOfflineHome {
+    
+    NSString *homeJsonPath = [self.offlineDir stringByAppendingPathComponent:@"home.json"];
+    NSDictionary *result = [self _loadCacheData:homeJsonPath];
+
+    return result;
+}
+
+/**
+ * @brief 加载离线首页数据
+ */
+- (NSDictionary *)requestOfflineHome {
+    Lock();
+    
+    NSDictionary *result = [self _requestOfflineHome];
+    
+    Unlock();
+    return result;
+}
+
+/**
+ * @brief 加载离线Detail
+ * @param orderId 订单号
+ * @param type 订单类型,包括 new order 和 processing order
+ */
+- (NSDictionary *)requestOfflineDetailForOrder:(NSString *)orderId withOrderType:(NSInteger)type {
+    Lock();
+    
+    NSString *detailJsonPath = [self.offlineDir stringByAppendingPathComponent:[NSString stringWithFormat:@"detail/%@_%ld",orderId,(long)type]];
+    NSMutableDictionary *detailJson = [[self _loadCacheData:detailJsonPath] mutableCopy];
+    
+    NSNumber *finish = [self _lastActionIndexForOrder:orderId];
+    
+    detailJson = [self filtrateActionFromDetail:detailJson withFinishActions:finish];
+    
+    Unlock();
+    return detailJson;
+}
+
+/**
+ * @brief 在detail中过滤订单已经做过的操作
+ * @param detail order detail界面数据
+ * @param finish order最后完成的一个action索引
+ */
+- (NSMutableDictionary *)filtrateActionFromDetail:(NSMutableDictionary *)detail withFinishActions:(NSNumber *)finish {
+    
+    if (finish == nil) {
+        return detail;
+    }
+    
+    int result = [[detail objectForKey:@"result"] intValue];
+    if (result != RESULT_TRUE) {
+        return detail;
+    }
+    
+    // 一层层解开,获取到目标值后z作出修改,然后反向一层层的套回去
+    NSMutableArray<NSDictionary *> *sections = [[detail objectForKey:@"sections"] mutableCopy];
+    [sections enumerateObjectsUsingBlock:^(NSDictionary * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
+       
+        NSMutableDictionary *section = [obj mutableCopy];
+        NSMutableArray<NSDictionary *> *values = [[section objectForKey:@"values"] mutableCopy];
+        [values enumerateObjectsUsingBlock:^(NSDictionary *  _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
+           
+            int type = [[obj objectForKey:@"type"] intValue];
+            if (type == RAOrderDetailValueTypeAction) {
+                NSMutableDictionary *mObj = [obj mutableCopy];
+                NSMutableArray<NSDictionary *> *actions = [[mObj objectForKey:@"actions"] mutableCopy];
+                NSMutableArray *rmArr = [NSMutableArray array];
+                [actions enumerateObjectsUsingBlock:^(NSDictionary * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
+                   
+                    NSInteger index = [[obj objectForKey:@"index"] integerValue];
+                    if ([finish integerValue] >= index) {
+                        [rmArr addObject:obj];
+                    }
+                    
+                }];
+                [actions removeObjectsInArray:rmArr];
+                [mObj setObject:actions forKey:@"actions"];
+                [values replaceObjectAtIndex:idx withObject:mObj];
+            }
+            
+            
+            
+        }];
+        [section setObject:values forKey:@"values"];
+        [sections replaceObjectAtIndex:idx withObject:section];
+    }];
+    [detail setObject:sections forKey:@"sections"];
+    
+    return detail;
+}
+
+/**
+ * @brief 记载离线Edit Order
+ * @param orderId 订单号
+ * @param actionIndex 操作标记
+ */
+- (NSDictionary *)requestOfflineEditOrder:(NSString *)orderId withAction:(NSInteger)actionIndex {
+    Lock();
+    
+    NSString *editJsonPath = [self.offlineDir stringByAppendingPathComponent:[NSString stringWithFormat:@"edit/%@_%ld",orderId,(long)actionIndex]];
+    NSDictionary *editJson = [self _loadCacheData:editJsonPath];
+    
+    Unlock();
+    return editJson;
+}
+
+/**
+ * @brief 最后一次修改Order的 Action 索引
+ * @param orderId 订单号
+ */
+- (NSNumber *)_lastActionIndexForOrder:(NSString *)orderId {
+    
+    NSDictionary *finishDic = [self _finishedActions];
+    NSNumber *finish = [finishDic objectForKey:orderId];
+    
+    return finish;
+}
+
+/**
+ * @brief 最后一次修改Order的 Action 索引
+ * @param orderId 订单号
+ */
+- (NSNumber *)lastActionIndexForOrder:(NSString *)orderId {
+    Lock();
+    
+    NSDictionary *finishDic = [self _finishedActions];
+    NSNumber *finish = [finishDic objectForKey:orderId];
+    
+    Unlock();
+    return finish;
+}
+
+@end

+ 1 - 1
Redant Drivers/Apex And Drivers/RADataProvider.h

@@ -20,7 +20,7 @@
 
 
 + (NSDictionary *)requestOrderDetail:(NSString *)orderID type:(NSInteger)type type2:(NSString *)type2 statusNo:(NSString *)statusNo;
 + (NSDictionary *)requestOrderDetail:(NSString *)orderID type:(NSInteger)type type2:(NSString *)type2 statusNo:(NSString *)statusNo;
 
 
-+ (NSDictionary *)requestUpdateOrder:(NSString *)orderID driverAction:(NSInteger)action;
++ (NSDictionary *)requestUpdateOrder:(NSString *)orderID driverAction:(NSInteger)action index:(NSInteger)idx;
 
 
 + (NSDictionary *)reportAcionToURL:(NSString *)url withParams:(NSMutableDictionary *)params;
 + (NSDictionary *)reportAcionToURL:(NSString *)url withParams:(NSMutableDictionary *)params;
 
 

+ 25 - 2
Redant Drivers/Apex And Drivers/RADataProvider.m

@@ -10,6 +10,7 @@
 #import "NetworkUtils.h"
 #import "NetworkUtils.h"
 #import "ZipArchive.h"
 #import "ZipArchive.h"
 #import "AESCrypt.h"
 #import "AESCrypt.h"
+#import "RAOfflineHandler.h"
 
 
 
 
 @implementation RADataProvider
 @implementation RADataProvider
@@ -174,6 +175,10 @@
 
 
 + (NSDictionary *)requestOrderList {
 + (NSDictionary *)requestOrderList {
     
     
+    if (RASingleton.sharedInstance.offline) {
+        return [[RAOfflineHandler defaultHandler] requestOfflineHome];
+    }
+    
     NSMutableDictionary *params = [NSMutableDictionary dictionary];
     NSMutableDictionary *params = [NSMutableDictionary dictionary];
     
     
     
     
@@ -199,6 +204,10 @@
 
 
 + (NSDictionary *)requestOrderDetail:(NSString *)orderID type:(NSInteger)type type2:(NSString *)type2 statusNo:(NSString *)statusNo {
 + (NSDictionary *)requestOrderDetail:(NSString *)orderID type:(NSInteger)type type2:(NSString *)type2 statusNo:(NSString *)statusNo {
     
     
+    if (RASingleton.sharedInstance.offline) {
+        return [[RAOfflineHandler defaultHandler] requestOfflineDetailForOrder:orderID withOrderType:type];
+    }
+    
     NSMutableDictionary *params = [NSMutableDictionary dictionary];
     NSMutableDictionary *params = [NSMutableDictionary dictionary];
     if (orderID) {
     if (orderID) {
         [params setObject:orderID forKey:@"orderID"];
         [params setObject:orderID forKey:@"orderID"];
@@ -213,10 +222,24 @@
     
     
     NSData* json=[self get_json:URL_DETAIL parameters:params  file:nil];
     NSData* json=[self get_json:URL_DETAIL parameters:params  file:nil];
     
     
-    return [self handleJsonData:json];
+    NSDictionary *detail = [self handleJsonData:json];
+    
+#ifdef OFFLINE_MODE
+    
+    NSNumber *finish = [[RAOfflineHandler defaultHandler] lastActionIndexForOrder:orderID];
+    detail = [[RAOfflineHandler defaultHandler] filtrateActionFromDetail:[detail mutableCopy] withFinishActions:finish];
+    
+#endif
+    
+    return detail;
 }
 }
 
 
-+ (NSDictionary *)requestUpdateOrder:(NSString *)orderID driverAction:(NSInteger)action {
++ (NSDictionary *)requestUpdateOrder:(NSString *)orderID driverAction:(NSInteger)action index:(NSInteger)idx {
+    
+    if (RASingleton.sharedInstance.offline) {
+        return [[RAOfflineHandler defaultHandler] requestOfflineEditOrder:orderID withAction:idx];
+    }
+    
 //    return [self loadFakeData:@"fake_order_edit.json"];
 //    return [self loadFakeData:@"fake_order_edit.json"];
     NSMutableDictionary *params = [NSMutableDictionary dictionary];
     NSMutableDictionary *params = [NSMutableDictionary dictionary];
     if (orderID) {
     if (orderID) {

+ 2 - 0
Redant Drivers/Apex And Drivers/RASingleton.h

@@ -37,6 +37,8 @@ typedef enum {
 
 
 @property (nonatomic,assign) RABackgroundReportType backgroundReportType;///<后台位置报告权限类型
 @property (nonatomic,assign) RABackgroundReportType backgroundReportType;///<后台位置报告权限类型
 
 
+@property (nonatomic,assign) BOOL offline;
+
 - (void)saveUserInfo;
 - (void)saveUserInfo;
 
 
 - (NSString *)savedUser;
 - (NSString *)savedUser;

+ 2 - 0
Redant Drivers/Apex And Drivers/Update/RAOrderEditViewController.h

@@ -13,9 +13,11 @@
 
 
 @property (nonatomic,copy) NSString *orderID;
 @property (nonatomic,copy) NSString *orderID;
 @property (nonatomic,assign) NSInteger actionID;
 @property (nonatomic,assign) NSInteger actionID;
+@property (nonatomic,assign) NSInteger actionIdx;
 @property (nonatomic,copy) NSString *actionTitle;
 @property (nonatomic,copy) NSString *actionTitle;
 @property (nonatomic,copy) NSString *orderType2;
 @property (nonatomic,copy) NSString *orderType2;
 
 
+
 @property (nonatomic,strong) NSIndexPath *editingIndexPath;
 @property (nonatomic,strong) NSIndexPath *editingIndexPath;
 
 
 - (NSUInteger)editSectionCount;
 - (NSUInteger)editSectionCount;

+ 2 - 1
Redant Drivers/Apex And Drivers/Update/RAOrderEditViewController.m

@@ -239,10 +239,11 @@
     
     
     NSString *orderID = self.orderID;
     NSString *orderID = self.orderID;
     NSInteger actionID = self.actionID;
     NSInteger actionID = self.actionID;
+    NSInteger actionIdx = self.actionIdx;
     __weak typeof(self) weakSelf = self;
     __weak typeof(self) weakSelf = self;
     dispatch_async(dispatch_get_global_queue(0, 0), ^{
     dispatch_async(dispatch_get_global_queue(0, 0), ^{
         
         
-        NSDictionary *json = [RADataProvider requestUpdateOrder:orderID driverAction:actionID];
+        NSDictionary *json = [RADataProvider requestUpdateOrder:orderID driverAction:actionID index:actionIdx];
         
         
         dispatch_async(dispatch_get_main_queue(), ^{
         dispatch_async(dispatch_get_main_queue(), ^{
             
             

+ 2 - 0
Redant Drivers/Apex And Drivers/config.h

@@ -9,6 +9,8 @@
 #ifndef config_h
 #ifndef config_h
 #define config_h
 #define config_h
 
 
+#define OFFLINE_MODE YES
+
 #define ApexDriverOrangeWhiteColor UIColorFromRGB(0xe65c00)
 #define ApexDriverOrangeWhiteColor UIColorFromRGB(0xe65c00)
 #define ApexDriverOrangeColor UIColorFromRGB(0xff8008)
 #define ApexDriverOrangeColor UIColorFromRGB(0xff8008)
 #define ApexDriverGrayColor UIColorFromRGB(0x4f5356)
 #define ApexDriverGrayColor UIColorFromRGB(0x4f5356)