Ver Fonte

1.完成iOS Apex Drivers离线Action提交数据。
2.修改iOS Apex Drivers More Order增加索引。

Pen Li há 7 anos atrás
pai
commit
84864ee831

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

@@ -295,7 +295,13 @@
     __weak typeof(self) weakSelf = self;
     dispatch_async(dispatch_get_global_queue(0, 0), ^{
         
-        NSDictionary *json = [RADataProvider reportAcionToURL:model.url withParams:model.params];
+        NSDictionary *json = [RADataProvider reportOrder:self.orderID
+                                                    type:self.orderType
+                                              actionType:model.actionID
+                                             actionIndex:model.index
+                                              actionName:model.actionTitle
+                                                   toURL:model.url
+                                              withParams:model.params];
         
         dispatch_async(dispatch_get_main_queue(), ^{
             

+ 23 - 10
Redant Drivers/Apex And Drivers/Home/Home.storyboard

@@ -1,11 +1,11 @@
 <?xml version="1.0" encoding="UTF-8"?>
-<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="14113" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
+<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="14313.18" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
     <device id="retina4_7" orientation="portrait">
         <adaptation id="fullscreen"/>
     </device>
     <dependencies>
         <deployment identifier="iOS"/>
-        <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="14088"/>
+        <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="14283.14"/>
         <capability name="Safe area layout guides" minToolsVersion="9.0"/>
         <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
     </dependencies>
@@ -58,7 +58,7 @@
                                                                     <nil key="highlightedColor"/>
                                                                 </label>
                                                                 <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="AFS180530001200" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="ZZd-1e-a8S">
-                                                                    <rect key="frame" x="73" y="0.0" width="222" height="17"/>
+                                                                    <rect key="frame" x="72.5" y="0.0" width="222.5" height="17"/>
                                                                     <fontDescription key="fontDescription" type="system" pointSize="14"/>
                                                                     <nil key="textColor"/>
                                                                     <nil key="highlightedColor"/>
@@ -137,7 +137,7 @@
                                                             </constraints>
                                                         </view>
                                                         <imageView userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="backend_flag" translatesAutoresizingMaskIntoConstraints="NO" id="Rxe-zz-m6W">
-                                                            <rect key="frame" x="340" y="5" width="20" height="20"/>
+                                                            <rect key="frame" x="340" y="5.5" width="20" height="20"/>
                                                             <constraints>
                                                                 <constraint firstAttribute="height" constant="20" id="G2B-kt-1dz"/>
                                                                 <constraint firstAttribute="width" constant="20" id="SmO-AW-5Qc"/>
@@ -235,8 +235,8 @@
                                                                 <constraint firstAttribute="height" constant="50" id="z9o-Ex-Ffd"/>
                                                             </constraints>
                                                         </imageView>
-                                                        <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Pickup Order New" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="6qD-i1-tev">
-                                                            <rect key="frame" x="10" y="5" width="139" height="21"/>
+                                                        <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Pickup Order New" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="6qD-i1-tev">
+                                                            <rect key="frame" x="65" y="5" width="270" height="21"/>
                                                             <constraints>
                                                                 <constraint firstAttribute="height" constant="21" id="GG4-X2-FoD"/>
                                                             </constraints>
@@ -261,7 +261,7 @@
                                                                     <nil key="highlightedColor"/>
                                                                 </label>
                                                                 <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="AFS180530001200" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="hNu-AY-bfS">
-                                                                    <rect key="frame" x="73" y="0.0" width="222" height="17"/>
+                                                                    <rect key="frame" x="72.5" y="0.0" width="222.5" height="17"/>
                                                                     <fontDescription key="fontDescription" type="system" pointSize="14"/>
                                                                     <nil key="textColor"/>
                                                                     <nil key="highlightedColor"/>
@@ -339,20 +339,32 @@
                                                                 <constraint firstItem="hZL-d6-pXB" firstAttribute="leading" secondItem="FLu-57-E2d" secondAttribute="leading" id="xyd-uk-3pa"/>
                                                             </constraints>
                                                         </view>
+                                                        <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="0" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="NTn-LM-Gkv">
+                                                            <rect key="frame" x="10" y="17" width="50" height="24"/>
+                                                            <constraints>
+                                                                <constraint firstAttribute="height" constant="24" id="gwv-Pw-VQD"/>
+                                                            </constraints>
+                                                            <fontDescription key="fontDescription" type="boldSystem" pointSize="17"/>
+                                                            <color key="textColor" red="0.93741904145077726" green="0.23165335489775699" blue="0.052563832690813113" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+                                                            <nil key="highlightedColor"/>
+                                                        </label>
                                                     </subviews>
                                                     <color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
                                                     <constraints>
+                                                        <constraint firstItem="NTn-LM-Gkv" firstAttribute="top" secondItem="Ez1-e3-yIq" secondAttribute="top" constant="17" id="1Ii-S9-I65"/>
+                                                        <constraint firstItem="wDi-Zy-4rB" firstAttribute="leading" secondItem="6qD-i1-tev" secondAttribute="trailing" constant="5" id="1WO-dZ-wze"/>
                                                         <constraint firstItem="wDi-Zy-4rB" firstAttribute="centerY" secondItem="6qD-i1-tev" secondAttribute="centerY" id="4Ot-oK-p45"/>
                                                         <constraint firstItem="iT9-Mg-UwI" firstAttribute="leading" secondItem="r8P-b3-SYP" secondAttribute="trailing" constant="5" id="6Ls-Et-nsC"/>
                                                         <constraint firstAttribute="trailing" secondItem="wDi-Zy-4rB" secondAttribute="trailing" constant="5" id="9CO-bv-pcD"/>
+                                                        <constraint firstItem="NTn-LM-Gkv" firstAttribute="width" secondItem="r8P-b3-SYP" secondAttribute="width" id="DWz-bh-l5o"/>
                                                         <constraint firstItem="r8P-b3-SYP" firstAttribute="centerY" secondItem="iT9-Mg-UwI" secondAttribute="centerY" id="TQt-hT-qBQ"/>
-                                                        <constraint firstItem="wDi-Zy-4rB" firstAttribute="leading" relation="greaterThanOrEqual" secondItem="6qD-i1-tev" secondAttribute="trailing" priority="999" constant="5" id="dOh-AW-rh3"/>
+                                                        <constraint firstItem="NTn-LM-Gkv" firstAttribute="leading" secondItem="r8P-b3-SYP" secondAttribute="leading" id="d25-4l-cDk"/>
                                                         <constraint firstItem="6qD-i1-tev" firstAttribute="top" secondItem="Ez1-e3-yIq" secondAttribute="top" constant="5" id="dpT-RF-kkz"/>
                                                         <constraint firstItem="iT9-Mg-UwI" firstAttribute="top" secondItem="6qD-i1-tev" secondAttribute="bottom" constant="8" id="fHt-7S-OuY"/>
-                                                        <constraint firstItem="6qD-i1-tev" firstAttribute="leading" secondItem="Ez1-e3-yIq" secondAttribute="leading" constant="10" id="fQ4-iB-Dey"/>
                                                         <constraint firstAttribute="bottom" secondItem="iT9-Mg-UwI" secondAttribute="bottom" id="jY3-w0-Ad3"/>
+                                                        <constraint firstItem="6qD-i1-tev" firstAttribute="leading" secondItem="NwP-AP-5zX" secondAttribute="leading" id="uSt-Mj-jNf"/>
                                                         <constraint firstItem="iT9-Mg-UwI" firstAttribute="trailing" secondItem="wDi-Zy-4rB" secondAttribute="trailing" id="yrN-v9-UOy"/>
-                                                        <constraint firstItem="r8P-b3-SYP" firstAttribute="leading" secondItem="6qD-i1-tev" secondAttribute="leading" id="zBB-26-ymt"/>
+                                                        <constraint firstItem="r8P-b3-SYP" firstAttribute="leading" secondItem="Ez1-e3-yIq" secondAttribute="leading" constant="10" id="zBB-26-ymt"/>
                                                     </constraints>
                                                 </view>
                                             </subviews>
@@ -371,6 +383,7 @@
                                             <outlet property="containerNoLabel" destination="Kd7-FH-8p2" id="Tcr-ch-u2z"/>
                                             <outlet property="contentContainer" destination="Ez1-e3-yIq" id="qKN-cW-0Ck"/>
                                             <outlet property="dateLabel" destination="Z8k-hS-sOz" id="iYz-xc-L6c"/>
+                                            <outlet property="indexLabel" destination="NTn-LM-Gkv" id="Vu6-xz-qYp"/>
                                             <outlet property="markView" destination="wDi-Zy-4rB" id="Ekf-Yy-ghj"/>
                                             <outlet property="orderNoLabel" destination="hNu-AY-bfS" id="0D3-Cf-5I0"/>
                                             <outlet property="orderType2Label" destination="1vU-Ly-MVu" id="Yb8-6d-lWK"/>

+ 2 - 1
Redant Drivers/Apex And Drivers/Home/More/RAHomeMoreViewController+TableDataSource.m

@@ -26,7 +26,8 @@
     
     RAHomeOrderModel *order = [self orderModelForIndexPath:indexPath];
     cell.orderModel = order;
-    
+    cell.index = indexPath.row + 1;
+
     return cell;
 }
 

+ 5 - 0
Redant Drivers/Apex And Drivers/Home/RAHomeOrderModel.h

@@ -33,6 +33,11 @@ typedef enum {
 @property (nonatomic,assign) BOOL backendFlag;
 @property (nonatomic,copy) NSString *status_no;
 
+@property (nonatomic,copy) NSString *color;///<orderTypeColor;
+@property (nonatomic,strong,readonly) UIColor *orderTypeColor;
+
+@property (nonatomic,copy) NSString *order_type;
+
 @property (nonatomic,strong,readonly) UIImage *icon;
 
 @property (nonatomic,weak) id<RAHomeOrderModelDelegate> delegate;

+ 22 - 0
Redant Drivers/Apex And Drivers/Home/RAHomeOrderModel.m

@@ -12,6 +12,7 @@
 
 @implementation RAHomeOrderModel {
     UIImage *_icon;
+    UIColor *_orderTypeColor;
 }
 
 - (void)setValue:(id)value forUndefinedKey:(NSString *)key {
@@ -22,6 +23,27 @@
     return _icon;
 }
 
+- (UIColor *)orderTypeColor {
+    if (!_orderTypeColor) {
+        _orderTypeColor = [UIColor blackColor];
+    }
+    return _orderTypeColor;
+}
+
+- (void)setColor:(NSString *)color {
+    _color = color;
+    
+    if ([color hasPrefix:@"#"]) {
+        color = [color stringByReplacingOccurrencesOfString:@"#" withString:@"0x"];
+    }
+    
+    if (![color hasPrefix:@"0x"]) {
+        _orderTypeColor = nil;
+    }
+    
+    _orderTypeColor = UIColorFromRGB(strtoul([color UTF8String], 0, 16));
+}
+
 - (void)setBackendFlag:(BOOL)backendFlag {
     _backendFlag = backendFlag;
     

+ 2 - 0
Redant Drivers/Apex And Drivers/Home/RAOrderCell.h

@@ -13,4 +13,6 @@
 
 @property (nonatomic,strong) RAHomeOrderModel *orderModel;
 
+@property (nonatomic,assign) NSUInteger index;
+
 @end

+ 17 - 2
Redant Drivers/Apex And Drivers/Home/RAOrderCell.m

@@ -19,6 +19,7 @@
 @property (strong, nonatomic) IBOutlet UIImageView *markView;
 @property (strong, nonatomic) IBOutlet UIImageView *statusView;
 @property (strong, nonatomic) IBOutlet UILabel *orderType2Label;
+@property (strong, nonatomic) IBOutlet UILabel *indexLabel;
 
 @property (nonatomic,strong) UIView *selectionView;
 
@@ -58,6 +59,7 @@
     [super prepareForReuse];
     
     [self setOrderModel:nil];
+    self.index = 0;
 }
 
 - (UIView *)selectionView {
@@ -77,6 +79,11 @@
 
 #pragma mark - Set
 
+- (void)setIndex:(NSUInteger)index {
+    _index = index;
+    self.indexLabel.text = [NSString stringWithFormat:@"%lu",index];
+}
+
 - (void)setOrderModel:(RAHomeOrderModel *)orderModel {
     _orderModel.delegate = nil;
     _orderModel = orderModel;
@@ -128,6 +135,13 @@
     return self;
 }
 
+- (instancetype)setOrderTypeColor:(UIColor *)color {
+    
+    self.orderType2Label.textColor = color;
+    
+    return self;
+}
+
 #pragma mark - Model Delegate
 
 - (void)refreshUI {
@@ -136,11 +150,12 @@
     NSString *orderNo = _orderModel.orderNo;
     NSString *containerNo = _orderModel.containerNo;
     NSString *date = _orderModel.date;
-    NSString *orderType2 = _orderModel.order_type2;
+    NSString *orderType = _orderModel.order_type;
     BOOL flag = _orderModel.backendFlag;
     UIImage *icon = _orderModel.icon;
+    UIColor *orderTypeColor = _orderModel.orderTypeColor;
     
-    [[[[[[[self setTitle:title] setOrderNo:orderNo] setContainerNo:containerNo] setDate:date] setBackendFlag:flag] setOrderType2:orderType2] setStatusIcon:icon];
+    [[[[[[[[self setTitle:title] setOrderNo:orderNo] setContainerNo:containerNo] setDate:date] setBackendFlag:flag] setOrderType2:orderType] setStatusIcon:icon] setOrderTypeColor:orderTypeColor];
     
 }
 

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

@@ -10,6 +10,7 @@
 
 NS_ASSUME_NONNULL_BEGIN
 
+@class RAEditImageBaseModel;
 @interface RAOfflineHandler : NSObject
 
 /**
@@ -22,6 +23,8 @@ NS_ASSUME_NONNULL_BEGIN
  */
 - (void)downloadOfflineData;
 
+#pragma mark - Get
+
 /**
  * @brief 加载离线首页数据
  */
@@ -57,6 +60,33 @@ NS_ASSUME_NONNULL_BEGIN
  */
 - (NSNumber *)lastActionIndexForOrder:(NSString *)orderId;
 
+#pragma mark - Update
+
+/**
+ * @brief 离线提交Detail Remote Action
+ * @param orderId 订单号
+ * @param type 订单类型 RAOrderStatus, New Order / Processing Order
+ * @param action 操作类型 RADetailActionSubType, Reject / Accept
+ * @param actionIdx 操作索引
+ * @param actionName 操作名称
+ * @param url 操作提交目标地址
+ * @param params 操作提交的参数
+ * @return 成功/失败
+ */
+- (NSDictionary *)reportOrder:(NSString *)orderId type:(NSInteger)type actionType:(NSInteger)action actionIndex:(NSInteger)actionIdx actionName:(NSString *)actionName withURL:(NSString *)url params:(NSDictionary *)params;
+
+/**
+ * @brief 离线提交订单
+ * @param orderId 订单号
+ * @param actionId 操作ID,RADetailActionSubType
+ * @param title 操作名称
+ * @param idx 操作索引
+ * @param params 订单填写的信息
+ * @param photos 待上传的图片模型数组
+ * @param dir 待上传的图片存储目录
+ */
+- (NSDictionary *)updateOrder:(NSString *)orderId action:(NSInteger)actionId title:(NSString *)title index:(NSInteger)idx withParams:(NSDictionary *)params photos:(NSArray<RAEditImageBaseModel *> *)photos cacheDir:(NSString *)dir;
+
 @end
 
 NS_ASSUME_NONNULL_END

+ 520 - 40
Redant Drivers/Apex And Drivers/Offline/RAOfflineHandler.m

@@ -10,6 +10,10 @@
 #import "NetworkUtils.h"
 #import "ZipArchive.h"
 #import "RADetailBaseModel.h"
+#import "RAHomeOrderModel.h"
+#import "RADetailActionModel.h"
+#import "AppDelegate.h"
+#import "RAEditImageBaseModel.h"
 
 #define Lock() dispatch_semaphore_wait(_lock, DISPATCH_TIME_FOREVER)
 #define Unlock() dispatch_semaphore_signal(_lock)
@@ -19,16 +23,22 @@ static dispatch_semaphore_t _lock;
 @interface RAOfflineHandler () {
     NSString *_offlineDir;
     NSString *_offlineTmp;
+    NSString *_offlineUploadDir;
+    NSString *_zipPassword;
 }
 
 @property (nonatomic,strong) NSMutableDictionary *detailCache;///< 缓存查看过的Detai
 @property (nonatomic,strong,readonly) NSString *offlineDir; ///< 缓存文件夹
 @property (nonatomic,strong,readonly) NSString *offlineTmp; ///< 临时保存解压文件的文件夹
+@property (nonatomic,strong,readonly) NSString *offlineUploadDir; ///<上传文件目录
+@property (nonatomic,copy,readonly) NSString *zipPassword; ///<压缩/解压 密码
 
 @end
 
 @implementation RAOfflineHandler
 
+#pragma mark - Handler
+
 + (instancetype)defaultHandler {
     static RAOfflineHandler *handler;
     static dispatch_once_t token;
@@ -65,15 +75,41 @@ static dispatch_semaphore_t _lock;
         
         NSFileManager *fm = [NSFileManager defaultManager];
         BOOL isDir = YES;
-        if ([fm fileExistsAtPath:_offlineDir isDirectory:&isDir] && isDir) {
+        if ([fm fileExistsAtPath:_offlineTmp isDirectory:&isDir] && isDir) {
             
         } else {
-            [fm createDirectoryAtPath:_offlineDir withIntermediateDirectories:NO attributes:nil error:nil];
+            [fm createDirectoryAtPath:_offlineTmp withIntermediateDirectories:YES attributes:nil error:nil];
         }
     }
     return _offlineTmp;
 }
 
+- (NSString *)offlineUploadDir {
+    if (!_offlineUploadDir) {
+        
+        _offlineUploadDir = [self.offlineDir stringByAppendingPathComponent:@"upload"];
+        
+        NSFileManager *fm = [NSFileManager defaultManager];
+        BOOL isDir = YES;
+        if ([fm fileExistsAtPath:_offlineUploadDir isDirectory:&isDir] && isDir) {
+            
+        } else {
+            [fm createDirectoryAtPath:_offlineUploadDir withIntermediateDirectories:YES attributes:nil error:nil];
+        }
+        
+    }
+    return _offlineUploadDir;
+}
+
+- (NSString *)zipPassword {
+    if (!_zipPassword) {
+        _zipPassword = @"usai";
+    }
+    return _zipPassword;
+}
+
+#pragma mark - Download
+
 /**
  * @brief 向服务器请求离线数据
  */
@@ -130,7 +166,7 @@ static dispatch_semaphore_t _lock;
         // 删除旧数据,除了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]) {
+            if (![obj isEqualToString:self.offlineTmp] || ![obj.lastPathComponent isEqualToString:@"finish"] || ![obj isEqualToString:self.offlineUploadDir]) {
                 [fm removeItemAtPath:obj error:nil];
             }
         }];
@@ -151,21 +187,6 @@ static dispatch_semaphore_t _lock;
     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的剔除
  */
@@ -195,16 +216,7 @@ static dispatch_semaphore_t _lock;
     [finishDic writeToFile:finishPath atomically:NO];
 }
 
-/**
- * @brief 加载所有完成的订单Action
- */
-- (NSDictionary<NSString *, NSNumber *> *)_finishedActions {
-    
-    NSString *path = [self.offlineDir stringByAppendingPathComponent:@"finish"];
-    NSDictionary *dic = [NSDictionary dictionaryWithContentsOfFile:path];
-    
-    return dic;
-}
+#pragma mark - Request Data
 
 /**
  * @brief 加载离线首页数据
@@ -248,6 +260,64 @@ static dispatch_semaphore_t _lock;
     return detailJson;
 }
 
+/**
+ * @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;
+}
+
+#pragma mark - Utils
+
+
+/**
+ * @brief 解压离线下载的压缩包
+ * @return 解压是否成功
+ */
+- (BOOL)_unzipOfflineZip:(NSString *)path toDir:(NSString *)to {
+    
+    ZipArchive *zip = [[ZipArchive alloc] init];
+    BOOL zipRes = [zip UnzipOpenFile:path Password:self.zipPassword];
+    if (zipRes) {
+        zipRes = [zip UnzipFileTo:to overWrite:YES];
+    }
+    [zip UnzipCloseFile];
+    
+    return zipRes;
+}
+
+/**
+ * @brief 压缩文件夹
+ * @param dir 被压缩文件夹
+ * @return 压缩文件路径
+ */
+- (NSString *)_zipDir:(NSString *)dir {
+    
+    NSString *name = [[dir lastPathComponent] stringByAppendingString:@".zip"];
+    NSString *zipFile = [[dir stringByDeletingLastPathComponent] stringByAppendingPathComponent:name];
+    
+    ZipArchive *zip = [[ZipArchive alloc] init];
+    [zip CreateZipFile2:zipFile Password:self.zipPassword];
+    
+    NSFileManager *fm = [NSFileManager defaultManager];
+    NSArray *list = [fm contentsOfDirectoryAtPath:dir error:nil];
+    for (NSString *imgPath in list) {
+        [zip addFileToZip:imgPath newname:imgPath.lastPathComponent];
+    }
+    
+    [zip CloseZipFile2];
+    
+    return zipFile;
+}
+
 /**
  * @brief 在detail中过滤订单已经做过的操作
  * @param detail order detail界面数据
@@ -264,21 +334,21 @@ static dispatch_semaphore_t _lock;
         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];
@@ -302,18 +372,59 @@ static dispatch_semaphore_t _lock;
 }
 
 /**
- * @brief 记载离线Edit Order
+ * @brief 判断Order Action是否是最后一步
  * @param orderId 订单号
- * @param actionIndex 操作标记
+ * @return YES/NO
  */
-- (NSDictionary *)requestOfflineEditOrder:(NSString *)orderId withAction:(NSInteger)actionIndex {
-    Lock();
+- (BOOL)isLastActionForOrder:(NSString *)orderId {
+    if (!orderId) {
+        return NO;
+    }
+    NSDictionary *detail = [self requestOfflineDetailForOrder:orderId withOrderType:RAOrderStatusProcessing];
+    int result = [[detail objectForKey:@"result"] intValue];
+    if (result != RESULT_TRUE) {
+        return NO;
+    }
     
-    NSString *editJsonPath = [self.offlineDir stringByAppendingPathComponent:[NSString stringWithFormat:@"edit/%@_%ld",orderId,(long)actionIndex]];
-    NSDictionary *editJson = [self _loadCacheData:editJsonPath];
+    __block BOOL isLast = NO;
+    NSMutableArray<NSDictionary *> *sections = [[detail objectForKey:@"sections"] mutableCopy];
+    [sections enumerateObjectsUsingBlock:^(NSDictionary * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
     
-    Unlock();
-    return editJson;
+        NSMutableDictionary *section = [obj mutableCopy];
+        NSMutableArray<NSDictionary *> *values = [[section objectForKey:@"values"] mutableCopy];
+        __block BOOL findAction = NO;
+        [values enumerateObjectsUsingBlock:^(NSDictionary *  _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
+            
+            int type = [[obj objectForKey:@"type"] intValue];
+            if (type == RAOrderDetailValueTypeAction) {
+                findAction = YES;
+                NSMutableDictionary *mObj = [obj mutableCopy];
+                NSMutableArray<NSDictionary *> *actions = [[mObj objectForKey:@"actions"] mutableCopy];
+                if (actions.count == 1) {
+                    isLast = YES;
+                }
+                *stop = YES;
+            }
+
+        }];
+        
+        if (findAction) {
+            *stop = YES;
+        }
+    }];
+    
+    return isLast;
+}
+
+/**
+ * @brief 加载所有完成的订单Action
+ */
+- (NSDictionary<NSString *, NSNumber *> *)_finishedActions {
+    
+    NSString *path = [self.offlineDir stringByAppendingPathComponent:@"finish"];
+    NSDictionary *dic = [NSDictionary dictionaryWithContentsOfFile:path];
+    
+    return dic;
 }
 
 /**
@@ -342,4 +453,373 @@ static dispatch_semaphore_t _lock;
     return finish;
 }
 
+/**
+ * @brief 删除文件
+ * @param path 待删除文件路径
+ */
+- (void)deleteFileAtPath:(NSString *)path {
+    Lock();
+    
+    NSFileManager *fm = [NSFileManager defaultManager];
+    if([fm fileExistsAtPath:path]) {
+        [fm removeItemAtPath:path error:nil];
+    }
+    
+    Unlock();
+}
+
+/**
+ * @brief 将字典以Json格式写入文件
+ * @param json 待写入字典数据
+ * @param path 写入文件路径
+ */
+- (void)_writeJson:(NSDictionary *)json toPath:(NSString *)path {
+    
+    NSData *data = [NSJSONSerialization dataWithJSONObject:json options:NSJSONWritingPrettyPrinted error:nil];
+    [data writeToFile:path atomically:NO];
+    
+}
+
+/**
+ * @brief 将字典以Json格式写入文件
+ * @param json 待写入字典数据
+ * @param path 写入文件路径
+ */
+- (void)writeJson:(NSDictionary *)json toPath:(NSString *)path {
+    
+    Lock();
+    
+    [self _writeJson:json toPath:path];
+    
+    Unlock();
+}
+
+/**
+ * @brief 当前时间字符串,格式 MM/DD/YYYY HH:mm
+ */
+- (NSString *)currentDate {
+    
+    NSDate *date = [NSDate date];
+    NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
+    formatter.dateFormat = @"MM/DD/YYYY HH:mm";
+    
+    return [formatter stringFromDate:date];
+}
+
+#pragma mark - Update Data
+
+/**
+ * @brief 更新离线缓存Home数据
+ * @param homeJson 新的Home数据
+ */
+- (void)updateHome:(NSDictionary *)homeJson {
+    
+    NSString *homeJsonPath = [self.offlineDir stringByAppendingPathComponent:@"home.json"];
+    [self writeJson:homeJson toPath:homeJsonPath];
+}
+
+/**
+ * @brief 更新order最后一次操作标记
+ * @param actionIdx 操作索引
+ * @param orderId 订单号
+ */
+- (void)updateLastAction:(NSInteger)actionIdx forOrder:(NSString *)orderId {
+    if (!orderId) {
+        return;
+    }
+    Lock();
+    NSMutableDictionary<NSString *, NSNumber *> *finishDic = [[self _finishedActions] mutableCopy];
+    Unlock();
+    
+    [finishDic setObject:@(actionIdx) forKey:orderId];
+    
+    NSString *path = [self.offlineDir stringByAppendingPathComponent:@"finish"];
+    [self writeJson:finishDic toPath:path];
+}
+
+/**
+ * @brief 删除order操作对应的json文件
+ * @param orderId 订单号
+ * @param actionIdx 操作索引
+ */
+- (void)deleteEditJsonFileForOrder:(NSString *)orderId withActionIndex:(NSInteger)actionIdx {
+    
+    NSString *editJsonPath = [self.offlineDir stringByAppendingPathComponent:[NSString stringWithFormat:@"edit/%@_%ld",orderId,(long)actionIdx]];
+    [self deleteFileAtPath:editJsonPath];
+}
+
+/**
+ * @brief 离线提交Detail Remote Action
+ * @param orderId 订单号
+ * @param type 订单类型 RAOrderStatus, New Order / Processing Order
+ * @param action 操作类型 RADetailActionSubType, Reject / Accept
+ * @param actionIdx 操作索引
+ * @param actionName 操作名称
+ * @param url 操作提交目标地址
+ * @param params 操作提交的参数
+ * @return 成功/失败
+ */
+- (NSDictionary *)reportOrder:(NSString *)orderId type:(NSInteger)type actionType:(NSInteger)action actionIndex:(NSInteger)actionIdx actionName:(NSString *)actionName withURL:(NSString *)url params:(NSDictionary *)params {
+    
+    // 组织参数
+    NSString *time = [self currentDate];
+    NSMutableDictionary *mParams = [params mutableCopy];
+    [mParams setObject:time forKey:@"date"];
+    
+    NSMutableDictionary *task = [@{
+                                   @"order" : orderId,
+                                   @"action" : actionName,
+                                   @"name" : actionName,
+                                   @"time" : time,
+                                   @"url" : url,
+                                   @"noFile" : @YES,
+                                   @"params" : params
+                                   } mutableCopy];
+//    @"file" : photoPath,
+
+    // 提交参数给UploadManager
+    AppDelegate *appDelegate = (AppDelegate *)[UIApplication sharedApplication].delegate;
+    [appDelegate.uploadManager addTask:task];
+    
+    // New Order
+    if (type == RAOrderStatusNew) {
+        
+        // 加载Home
+        NSMutableDictionary *home = [[self requestOfflineHome] mutableCopy];
+        
+        // 遍历order,查找当前order,并修改状态/移除
+        // Accept 移动order到processing
+        // Reject 删除Order及对应的detail、edit
+        NSMutableArray<NSDictionary *> *sections = [[home objectForKey:@"sections"] mutableCopy];
+        __block NSDictionary *curOrder = nil; // 当前order
+        __block NSDictionary *rmSection = nil; // 若section下没有order,则移除section
+        // 查找New Order
+        for (int i = 0; i < sections.count; i++) {
+            NSDictionary *section = [sections objectAtIndex:i];
+            
+            RAOrderStatus type = [[section objectForKey:@"type"] intValue];
+            if (type == RAOrderStatusNew) {
+                
+                // 查找当前order
+                NSMutableArray<NSDictionary *> *orders = [[section objectForKey:@"orders"] mutableCopy];
+                [orders enumerateObjectsUsingBlock:^(NSDictionary * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
+                   
+                    NSString *orderID = [obj objectForKey:@"orderID"];
+                    if ([orderId isEqualToString:orderID]) {
+                        curOrder = obj;
+                        *stop = YES;
+                    }
+                }];
+                
+                // 找到order并移除
+                if (curOrder) {
+                    [orders removeObject:curOrder];
+                    
+                    // 移除过后如果orders为空,则移除section
+                    if (orders.count == 0) {
+                        rmSection = section;
+                    }
+                    else {
+                        // orders不为空,重新修改
+                        rmSection = nil;
+                        NSMutableDictionary *mSec = [section mutableCopy];
+                        [mSec setObject:orders forKey:@"orders"];
+                        [sections replaceObjectAtIndex:i withObject:mSec];
+                    }
+                }
+                
+                // 删除Order 操作对应Edit文件
+                [self deleteEditJsonFileForOrder:orderId withActionIndex:actionIdx];
+                
+                break;
+            }
+        }
+        
+        if (rmSection) {
+            [sections removeObject:rmSection];
+        }
+        
+        // 如果是Accept则将order添加到Processing Order
+        if (action == RADetailActionSubTypeAccept) {
+            
+            for (int i = 0; i < sections.count; i++) {
+                NSMutableDictionary *section = [[sections objectAtIndex:i] mutableCopy];
+                
+                RAOrderStatus type = [[section objectForKey:@"type"] intValue];
+                if (type == RAOrderStatusProcessing) {
+                    NSMutableArray<NSDictionary *> *orders = [[section objectForKey:@"orders"] mutableCopy];
+                    
+                    // 修改order状态为Processing
+                    [curOrder setValue:@(RAOrderStatusProcessing) forKey:@"status"];
+                    
+                    // 将当前order插入第一个位置
+                    [orders insertObject:curOrder atIndex:0];
+                    
+                    [section setObject:orders forKey:@"orders"];
+                    
+                    // 重新生成section
+                    [sections replaceObjectAtIndex:i withObject:section];
+                    break;
+                }
+            }
+        }
+        
+        // 重新生成sections
+        [home setObject:sections forKey:@"sections"];
+        
+        // 更新Home文件
+        [self updateHome:home];
+    }
+    
+    // 更新Action
+    [self updateLastAction:actionIdx forOrder:orderId];
+    
+    return @{
+             @"result" : @(RESULT_TRUE)
+             };
+}
+
+/**
+ * @brief 离线提交订单
+ * @param orderId 订单号
+ * @param actionId 操作ID,RADetailActionSubType
+ * @param title 操作名称
+ * @param idx 操作索引
+ * @param params 订单填写的信息
+ * @param photos 待上传的图片模型数组
+ * @param dir 待上传的图片存储目录
+ */
+- (NSDictionary *)updateOrder:(NSString *)orderId action:(NSInteger)actionId title:(NSString *)title index:(NSInteger)idx withParams:(NSDictionary *)params photos:(NSArray<RAEditImageBaseModel *> *)photos cacheDir:(NSString *)dir {
+    
+    Lock();
+    
+    NSFileManager *fm = [NSFileManager defaultManager];
+    // 生成上传目录
+    NSString *upDir = [self.offlineUploadDir stringByAppendingPathComponent:[NSString stringWithFormat:@"%@_%ld",orderId,(long)idx]];
+    [fm createDirectoryAtPath:upDir withIntermediateDirectories:NO attributes:nil error:nil];
+    
+    // 修改Params
+    NSString *time = [self currentDate];
+    NSMutableDictionary *mParams = [params mutableCopy];
+    [mParams setObject:@"time" forKey:@"date"];
+    [mParams setObject:@(1) forKey:@"offline"];
+
+//    // 将params写入目录
+//    NSString *paramPath = [upDir stringByAppendingPathComponent:@"params.json"];
+//    [self _writeJson:mParams toPath:paramPath];
+    
+    if (photos.count > 0) {
+        // 生成图片目录
+        NSString *imageDir = [upDir stringByAppendingPathComponent:@"images"];
+        [fm createDirectoryAtPath:imageDir withIntermediateDirectories:NO attributes:nil error:nil];
+        
+        // 将图片移动到图片目录
+        for (RAEditImageBaseModel *model in photos) {
+            NSString *path = [dir stringByAppendingPathComponent:model.imageName];
+            NSString *toPath = [imageDir stringByAppendingString:model.imageName];
+            
+            if ([fm fileExistsAtPath:path]) {
+                
+                NSError *err;
+                BOOL move = [fm moveItemAtPath:path toPath:toPath error:&err];
+                if (!move) {
+                    
+                    NSString *msg = @"Sorry,there is something error";
+                    if (err) {
+                        msg = err.localizedDescription;
+                    }
+                    
+                    Unlock();
+                    return @{
+                             @"result" : @(RESULT_FALSE),
+                             @"err_msg" : msg
+                             };
+                }
+                
+            }
+        }
+    }
+    
+    // 压缩目录
+    NSString *zip = [self _zipDir:upDir];
+    
+    // 删除目录
+    [fm removeItemAtPath:upDir error:nil];
+    
+    Unlock();
+    
+    // 创建Task
+    NSMutableDictionary *task = [@{
+                                   @"order" : orderId,
+                                   @"action" : title,
+                                   @"name" : title,
+                                   @"time" : time,
+                                   @"url" : URL_UPLOAD,
+                                   @"file" : zip,
+                                   @"params" : mParams
+                                   } mutableCopy];
+    
+    // 提交Task
+    AppDelegate *appDelegate = (AppDelegate *)[UIApplication sharedApplication].delegate;
+    [appDelegate.uploadManager addTask:task];
+    
+    // 判断是否完成order 所有操作
+    BOOL finish = [self isLastActionForOrder:orderId];
+    if (finish) {
+        // 将order从Processing中删除
+        // 加载Home
+        NSMutableDictionary *home = [[self requestOfflineHome] mutableCopy];
+        
+        NSMutableArray<NSDictionary *> *sections = [[home objectForKey:@"sections"] mutableCopy];
+        __block NSDictionary *rmSection = nil; // 若section下没有order,则移除section
+        for (int i = 0; i < sections.count; i++) {
+            NSMutableDictionary *section = [[sections objectAtIndex:i] mutableCopy];
+            
+            RAOrderStatus type = [[section objectForKey:@"type"] intValue];
+            if (type == RAOrderStatusProcessing) {
+                NSMutableArray<NSDictionary *> *orders = [[section objectForKey:@"orders"] mutableCopy];
+                
+                __block NSDictionary *curOrder = nil; // 当前order
+                [orders enumerateObjectsUsingBlock:^(NSDictionary * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
+                   
+                    NSString *orderID = [obj objectForKey:@"orderID"];
+                    if ([orderId isEqualToString:orderID]) {
+                        curOrder = obj;
+                        *stop = YES;
+                    }
+                    
+                }];
+                [orders removeObject:curOrder];
+                
+                if (orders.count > 0) {
+                    [section setObject:orders forKey:@"orders"];
+                    
+                    // 重新生成section
+                    [sections replaceObjectAtIndex:i withObject:section];
+                } else {
+                    
+                    rmSection = [sections objectAtIndex:i];
+                }
+                
+                break;
+            }
+        }
+        
+        if (rmSection) {
+            [sections removeObject:rmSection];
+        }
+        
+        // 重新生成sections
+        [home setObject:sections forKey:@"sections"];
+        
+        // 更新Home文件
+        [self updateHome:home];
+    }
+    
+    return @{
+             @"result" : @(RESULT_TRUE),
+             @"err_msg" : [NSString stringWithFormat:@"%@ %@ is submitted,you will find it in upload list.",title,orderId]
+             };
+}
+
 @end

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

@@ -8,6 +8,7 @@
 
 #import <Foundation/Foundation.h>
 
+@class RAEditImageBaseModel;
 @interface RADataProvider : NSObject
 
 + (NSDictionary *)requestLogin:(NSString *)user password:(NSString *)pwd;
@@ -22,7 +23,7 @@
 
 + (NSDictionary *)requestUpdateOrder:(NSString *)orderID driverAction:(NSInteger)action index:(NSInteger)idx;
 
-+ (NSDictionary *)reportAcionToURL:(NSString *)url withParams:(NSMutableDictionary *)params;
++ (NSDictionary *)reportOrder:(NSString *)orderId type:(NSInteger)type actionType:(NSInteger)action actionIndex:(NSInteger)actionIndex actionName:(NSString *)actionName toURL:(NSString *)url withParams:(NSMutableDictionary *)params;
 
 + (NSDictionary *)submitEditOrder:(NSMutableDictionary *)params;
 
@@ -47,4 +48,6 @@
 
 + (NSDictionary *)requestMessage:(NSInteger)offset limit:(NSInteger)limit unread:(BOOL)unread;
 
++ (NSDictionary *)offlineSubmitOrder:(NSString *)orderId action:(NSInteger)actionId title:(NSString *)title index:(NSInteger)idx withParams:(NSDictionary *)params photos:(NSArray<RAEditImageBaseModel *> *)photos cacheDir:(NSString *)dir;
+
 @end

+ 13 - 1
Redant Drivers/Apex And Drivers/RADataProvider.m

@@ -262,13 +262,25 @@
     return [self handleJsonData:json];
 }
 
-+ (NSDictionary *)reportAcionToURL:(NSString *)url withParams:(NSMutableDictionary *)params {
++ (NSDictionary *)reportOrder:(NSString *)orderId type:(NSInteger)type actionType:(NSInteger)action actionIndex:(NSInteger)actionIndex actionName:(NSString *)actionName toURL:(NSString *)url withParams:(NSMutableDictionary *)params {
+    
+    if (RASingleton.sharedInstance.offline) {
+        NSDictionary *result = [[RAOfflineHandler defaultHandler] reportOrder:orderId type:type actionType:action actionIndex:actionIndex actionName:actionName withURL:url params:params];
+        if (result) {
+            return result;
+        }
+    }
     
     NSData* json=[self get_json:url parameters:params  file:nil];
     
     return [self handleJsonData:json];
 }
 
++ (NSDictionary *)offlineSubmitOrder:(NSString *)orderId action:(NSInteger)actionId title:(NSString *)title index:(NSInteger)idx withParams:(NSDictionary *)params photos:(NSArray<RAEditImageBaseModel *> *)photos cacheDir:(NSString *)dir {
+    
+    return [[RAOfflineHandler defaultHandler] updateOrder:orderId action:actionId title:title index:idx withParams:params photos:photos cacheDir:dir];
+}
+
 + (NSDictionary *)submitEditOrder:(NSMutableDictionary *)params {
     
     if (![params isKindOfClass:[NSMutableDictionary class]]) {

+ 50 - 28
Redant Drivers/Apex And Drivers/Update/RAOrderEditViewController.m

@@ -21,7 +21,6 @@
 #import "UIScrollView+Empty.h"
 #import "RAEmptyView.h"
 #import "RAEditRequiredAlert.h"
-
 #import <CoreLocation/CoreLocation.h>
 
 @interface RAEditSectionModel : NSObject
@@ -330,46 +329,62 @@
         return;
     }
     
+    
+    
     // show progress
     RAProgressHUD *hud = [RAProgressHUD showHUDOnView:self.view];
     
     __weak typeof(self) weakSelf = self;
     dispatch_async(dispatch_get_global_queue(0, 0), ^{
         
-        NSDictionary *json = [RADataProvider submitEditOrder:params];
-        
-        if (weakSelf) {
-            __strong typeof(weakSelf) strongSelf = weakSelf;
+        if (RASingleton.sharedInstance.offline) { // 离线
+            
+            NSDictionary *json = [weakSelf offlineUpdate:params photos:photoArr];
             
-            int result = [[json objectForKey:@"result"] intValue];
-            if (result == RESULT_TRUE) {
+            [hud dismiss:^{
                 
-                BOOL requiredLocation = [[json objectForKey:@"requiredLocation"] boolValue];
-                [RASingleton sharedInstance].requiredLocation = requiredLocation;
+                NSString *msg = [json objectForKey:@"err_msg"];
+                [weakSelf showAlertTilte:@"Warning" message:msg];
+            }];
+        }
+        else { // 在线
+            
+            NSDictionary *json = [RADataProvider submitEditOrder:params];
+            
+            if (weakSelf) {
+                __strong typeof(weakSelf) strongSelf = weakSelf;
                 
-                dispatch_async(dispatch_get_main_queue(), ^{
+                int result = [[json objectForKey:@"result"] intValue];
+                if (result == RESULT_TRUE) {
                     
-                    if (photoArr.count > 0) {
-                        [strongSelf syncUploadPhotos:photoArr Json:json HUD:hud];
-                    } else {
-                        [self gobackHome];
-                    }
-                });
-                
-            } else {
-                // process error
-                dispatch_async(dispatch_get_main_queue(), ^{
+                    BOOL requiredLocation = [[json objectForKey:@"requiredLocation"] boolValue];
+                    [RASingleton sharedInstance].requiredLocation = requiredLocation;
                     
-                    // dismiss progress
-                    [hud dismiss:^{
+                    dispatch_async(dispatch_get_main_queue(), ^{
                         
-                        NSString *msg = [json objectForKey:@"err_msg"];
-                        [strongSelf showAlertTilte:@"Warning" message:msg];
-                    }];
-
-                });
-
+                        if (photoArr.count > 0) {
+                            [strongSelf syncUploadPhotos:photoArr Json:json HUD:hud];
+                        } else {
+                            [self gobackHome];
+                        }
+                    });
+                    
+                } else {
+                    // process error
+                    dispatch_async(dispatch_get_main_queue(), ^{
+                        
+                        // dismiss progress
+                        [hud dismiss:^{
+                            
+                            NSString *msg = [json objectForKey:@"err_msg"];
+                            [strongSelf showAlertTilte:@"Warning" message:msg];
+                        }];
+                        
+                    });
+                    
+                }
             }
+            
         }
         
         
@@ -711,4 +726,11 @@
 //    return task;
 //}
 
+#pragma mark - Offline
+
+- (NSDictionary *)offlineUpdate:(NSDictionary *)params photos:(NSArray *)photos {
+    
+    return [RADataProvider offlineSubmitOrder:self.orderID action:self.actionID title:self.actionTitle index:self.actionIdx withParams:params photos:photos cacheDir:self.photoDir];
+}
+
 @end