// // 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 "RADetailBaseModel.h" #import "RAHomeOrderModel.h" #import "RADetailActionModel.h" #import "AppDelegate.h" #import "RAEditImageBaseModel.h" #import "RAArchiver.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; 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; dispatch_once(&token, ^{ handler = [[RAOfflineHandler alloc] init]; _lock = dispatch_semaphore_create(1); }); return handler; } - (void)prepareParams:(NSMutableDictionary* )params { NSAssert(params != nil, @"params can't be nil"); NSString *user = RASingleton.sharedInstance.encryptUser; NSString *password = RASingleton.sharedInstance.encryptPassword; if (user.length && password.length) { [params setObject:user forKey:@"name"]; [params setObject:password forKey:@"password"]; } [params setObject:@"iOS" forKey:@"platform"]; NSDictionary* infoDict =[[NSBundle mainBundle] infoDictionary]; NSString* short_version =[infoDict objectForKey:@"CFBundleShortVersionString"]; [params setValue:short_version forKey:@"app_short_ver"]; NSString *localeLanguageCode = [[NSLocale currentLocale] objectForKey:NSLocaleLanguageCode]; [params setValue:localeLanguageCode forKey:@"language"]; NSString *time = [self currentDate]; [params setObject:time forKey:@"date"]; [params setObject:@(1) forKey:@"offline"]; #if TARGET_IPHONE_SIMULATOR//模拟器 [params setValue:@"simulator_uuid" forKey:@"deviceid"]; #elif TARGET_OS_IPHONE//真机 UIDevice * dev = [UIDevice currentDevice]; NSUUID* uuid =dev.identifierForVendor; [params setValue:uuid.UUIDString forKey:@"deviceid"]; #endif } - (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:_offlineTmp isDirectory:&isDir] && isDir) { } else { [fm createDirectoryAtPath:_offlineTmp withIntermediateDirectories:YES attributes:nil error:nil]; } } return _offlineTmp; } - (NSString *)offlineUploadDir { if (!_offlineUploadDir) { NSString *docDir = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) firstObject]; _offlineUploadDir = [docDir 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 向服务器请求离线数据 */ - (void)downloadOfflineData { dispatch_async(dispatch_get_global_queue(0, 0), ^{ NSMutableDictionary *params = [NSMutableDictionary dictionary]; [self prepareParams:params]; [NetworkUtils downloadFileOffset:0 Param:params from:@"http://192.168.0.130/fake_offline.zip" 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]; } }]; // NSString *path = [self.offlineDir stringByAppendingPathComponent:@"download.zip"]; // [self handleDownloadFile:path]; // }); } /** * @brief 加载沙盒中的数据 * @param path 沙盒数据路径 */ - (NSDictionary *)_loadCacheData:(NSString *)path { if (path == nil || path.length == 0) { return nil; } NSData *data = [NSData dataWithContentsOfFile:path]; if (data) { NSDictionary *dic = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableContainers error:nil]; return dic; } return nil; } - (void)_moveFile:(NSString *)filePath toFolder:(NSString *)folder { NSFileManager *fm = [NSFileManager defaultManager]; BOOL isDir = NO; if ([fm fileExistsAtPath:filePath isDirectory:&isDir] && !isDir) { BOOL fIsDir = NO; if ([fm fileExistsAtPath:folder isDirectory:&fIsDir] && fIsDir) { } else { NSError *err = nil; [fm createDirectoryAtPath:folder withIntermediateDirectories:YES attributes:nil error:&err]; if (err) { NSLog(@"create folder error: %@",err); return; } } NSString *to = [folder stringByAppendingPathComponent:filePath.lastPathComponent]; NSError *err = nil; [fm moveItemAtPath:filePath toPath:to error:&err]; if (err) { NSLog(@"move file error: %@",err); } } } - (void)_moveFolder:(NSString *)srcfolder toFolder:(NSString *)destFolder { NSFileManager *fm = [NSFileManager defaultManager]; BOOL isDir = NO; if ([fm fileExistsAtPath:srcfolder isDirectory:&isDir] && isDir) { NSString *dest = [destFolder stringByAppendingPathComponent:srcfolder.lastPathComponent]; isDir = NO; if ([fm fileExistsAtPath:dest isDirectory:&isDir] && isDir) { } else { NSError *err = nil; [fm createDirectoryAtPath:dest withIntermediateDirectories:YES attributes:nil error:&err]; if (err) { NSLog(@"create folder error: %@",err); return; } } NSArray *contents = [fm contentsOfDirectoryAtPath:srcfolder error:nil]; if (contents.count > 0) { [contents enumerateObjectsUsingBlock:^(NSString * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) { NSString *path = [srcfolder stringByAppendingPathComponent:obj]; BOOL fileIsDir = NO; if ([fm fileExistsAtPath:path isDirectory:&fileIsDir]) { if (fileIsDir) { [self _moveFolder:path toFolder:dest]; } else { [self _moveFile:path toFolder:dest]; } } }]; } } } /** * @brief 处理下载的压缩文件 * @param path 压缩文件路径 */ - (void)handleDownloadFile:(NSString *)path { Lock(); // 解压 BOOL zipRes = [self _unzipOfflineZip:path toDir:self.offlineTmp]; if (zipRes) { NSFileManager *fm = [NSFileManager defaultManager]; // 删除旧数据,除了tmp NSArray *items = [fm contentsOfDirectoryAtPath:self.offlineDir error:nil]; [items enumerateObjectsUsingBlock:^(NSString * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) { NSString *path = [self.offlineDir stringByAppendingPathComponent:obj]; if (![path isEqualToString:self.offlineTmp] && ![path.lastPathComponent isEqualToString:@"finish"] && ![path isEqualToString:self.offlineUploadDir]) { [fm removeItemAtPath:path error:nil]; } }]; // 将tmp中解压数据移出来 items = [fm contentsOfDirectoryAtPath:self.offlineTmp error:nil]; [items enumerateObjectsUsingBlock:^(NSString * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) { NSString *src = [self.offlineTmp stringByAppendingPathComponent:obj]; BOOL isDir = NO; if ([fm fileExistsAtPath:src isDirectory:&isDir]) { if (isDir) { [self _moveFolder:src toFolder:self.offlineDir]; } else { [self _moveFile:src toFolder:self.offlineDir]; } } }]; // 重置缓存的action [self _resetFinish]; } Unlock(); } /** * @brief 重置离线完成的Action,将finished order对应的action的剔除 */ - (void)_resetFinish { NSDictionary *homeJson = [self _requestOfflineHome]; NSArray *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 *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]; } #pragma mark - Request Data /** * @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 记载离线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 { return [RAArchiver ra_unzipOfflineZip:path toDir:to withPassword:self.zipPassword]; } /** * @brief 压缩文件夹 * @param dir 被压缩文件夹 * @return 压缩文件路径 */ - (NSString *)_zipDir:(NSString *)dir { NSString *zipFile = [dir stringByAppendingPathExtension:@"zip"]; if ([RAArchiver ra_zipFile:dir withPassword:self.zipPassword]) { return zipFile; } return nil; } /** * @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; } // 一层层解开,获取到目标值后作出修改,然后反向一层层的套回去 NSMutableArray *sections = [[detail objectForKey:@"sections"] mutableCopy]; NSMutableIndexSet *rmSectionArr = [NSMutableIndexSet indexSet]; [sections enumerateObjectsUsingBlock:^(NSDictionary * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) { NSMutableDictionary *section = [obj mutableCopy]; NSMutableArray *values = [[section objectForKey:@"values"] mutableCopy]; NSMutableIndexSet *rmValueArr = [NSMutableIndexSet indexSet]; [values enumerateObjectsUsingBlock:^(NSDictionary * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) { int type = [[obj objectForKey:@"type"] intValue]; if (type == RAOrderDetailValueTypeAction) { NSMutableDictionary *mObj = [obj mutableCopy]; NSMutableArray *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]; if (actions.count == 0) { [rmValueArr addIndex:idx]; } [mObj setObject:actions forKey:@"actions"]; [values replaceObjectAtIndex:idx withObject:mObj]; } }]; if (rmValueArr.count > 0) { [values removeObjectsAtIndexes:rmValueArr]; } if (values.count == 0) { [rmSectionArr addIndex:idx]; } [section setObject:values forKey:@"values"]; [sections replaceObjectAtIndex:idx withObject:section]; }]; if (rmSectionArr.count > 0) { [sections removeObjectsAtIndexes:rmSectionArr]; } [detail setObject:sections forKey:@"sections"]; return detail; } /** * @brief 判断Order Action是否是最后一步 * @param orderId 订单号 * @return YES/NO */ - (BOOL)isLastActionForOrder:(NSString *)orderId index:(NSInteger)actionIndex { if (!orderId) { return NO; } NSDictionary *detail = [self requestOfflineDetailForOrder:orderId withOrderType:RAOrderStatusProcessing]; int result = [[detail objectForKey:@"result"] intValue]; if (result != RESULT_TRUE) { return NO; } __block BOOL isLast = NO; NSMutableArray *sections = [[detail objectForKey:@"sections"] mutableCopy]; [sections enumerateObjectsUsingBlock:^(NSDictionary * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) { NSMutableDictionary *section = [obj mutableCopy]; NSMutableArray *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 *actions = [[mObj objectForKey:@"actions"] mutableCopy]; __block int maxActionIndex = 0; [actions enumerateObjectsUsingBlock:^(NSDictionary * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) { int index = [[obj objectForKey:@"index"] intValue]; maxActionIndex = MAX(maxActionIndex, index); }]; if (actionIndex == maxActionIndex) { isLast = YES; } *stop = YES; } }]; if (findAction) { *stop = YES; } }]; return isLast; } /** * @brief 加载所有完成的订单Action */ - (NSDictionary *)_finishedActions { NSString *path = [self.offlineDir stringByAppendingPathComponent:@"finish"]; NSDictionary *dic = [NSDictionary dictionaryWithContentsOfFile:path]; if (dic == nil) { dic = [NSDictionary dictionary]; } return dic; } /** * @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; } /** * @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]; } - (NSString *)statusTitleForActionIndex:(NSInteger)actionIndex { Lock(); NSString *path = [self.offlineDir stringByAppendingPathComponent:@"status_title.json"]; NSDictionary *titleDic = [self _loadCacheData:path]; Unlock(); NSString *title = [titleDic objectForKey:[NSString stringWithFormat:@"%ld",(long)actionIndex]]; if (!title) { title = @""; } return title; } - (NSString *)homeSectionTitleForStatus:(NSInteger)status { Lock(); NSString *path = [self.offlineDir stringByAppendingPathComponent:@"home_section_title.json"]; NSDictionary *titleDic = [self _loadCacheData:path]; Unlock(); NSString *title = [titleDic objectForKey:[NSString stringWithFormat:@"%ld",(long)status]]; if (!title) { title = @""; } return title; } - (void)homeSection:(NSMutableDictionary *)section addOrder:(NSDictionary *)curOrder forActionIndex:(NSInteger)actionIdx { if (curOrder == nil) { return; } NSMutableArray *orders = [[section objectForKey:@"orders"] mutableCopy]; if (orders == nil) { orders = [NSMutableArray array]; } // 修改order状态为Processing [curOrder setValue:@(RAOrderStatusProcessing) forKey:@"status"]; [curOrder setValue:@(NO) forKey:@"backendFlag"]; [curOrder setValue:[self statusTitleForActionIndex:actionIdx] forKey:@"title"]; // 将当前order插入第一个位置 [orders insertObject:curOrder atIndex:0]; [section setObject:orders forKey:@"orders"]; } #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 *finishDic = [[self _finishedActions] mutableCopy]; Unlock(); [finishDic setObject:@(actionIdx) forKey:orderId]; NSString *path = [self.offlineDir stringByAppendingPathComponent:@"finish"]; [finishDic writeToFile:path atomically:NO]; } /** * @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]; [self prepareParams:mParams]; NSMutableDictionary *task = [@{ @"order" : orderId, @"action" : actionName, @"name" : actionName, @"time" : time, @"url" : url, @"noFile" : @YES, @"params" : mParams } mutableCopy]; dispatch_async(dispatch_get_main_queue(), ^{ // @"file" : photoPath, // 提交参数给UploadManager AppDelegate *appDelegate = (AppDelegate *)[UIApplication sharedApplication].delegate; [appDelegate.uploadManager addTask:task]; }); // New Order if (type == RAOrderStatusNew) { // 加载Home NSMutableDictionary *home = [[self requestOfflineHome] mutableCopy]; if (home != nil) { // 遍历order,查找当前order,并修改状态/移除 // Accept 移动order到processing // Reject 删除Order及对应的detail、edit NSMutableArray *sections = [[home objectForKey:@"sections"] mutableCopy]; __block NSDictionary *curOrder = nil; // 当前order __block NSDictionary *rmSection = nil; // 若section下没有order,则移除section if (sections) { // 查找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 *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) { BOOL findSection = NO; for (int i = 0; i < sections.count; i++) { NSMutableDictionary *section = [[sections objectAtIndex:i] mutableCopy]; RAOrderStatus type = [[section objectForKey:@"type"] intValue]; if (type == RAOrderStatusProcessing) { [self homeSection:section addOrder:curOrder forActionIndex:actionIdx]; // 重新生成section [sections replaceObjectAtIndex:i withObject:section]; findSection = YES; break; } } if (!findSection) { NSMutableDictionary *section = [@{ @"type" : @(RAOrderStatusProcessing), @"totalCount" : @0, @"backendFlagCount" : @0, @"title" : [self homeSectionTitleForStatus:RAOrderStatusProcessing] } mutableCopy]; [self homeSection:section addOrder:curOrder forActionIndex:actionIdx]; [sections addObject:section]; } } // 重新生成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 *)photos cacheDir:(NSString *)dir { NSFileManager *fm = [NSFileManager defaultManager]; // 修改Params NSString *time = [self currentDate]; NSMutableDictionary *mParams = [params mutableCopy]; [self prepareParams:mParams]; // // 将params写入目录 // NSString *paramPath = [upDir stringByAppendingPathComponent:@"params.json"]; // [self _writeJson:mParams toPath:paramPath]; NSString *zipF = nil; if (photos.count > 0) { Lock(); // 生成上传目录 NSString *upDir = [self.offlineUploadDir stringByAppendingPathComponent:[NSString stringWithFormat:@"%@_%ld",orderId,(long)idx]]; [fm createDirectoryAtPath:upDir withIntermediateDirectories:NO attributes:nil error:nil]; // 生成图片目录 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 = NSLocalizedString(@"sorry", nil); if (err) { msg = err.localizedDescription; } Unlock(); return @{ @"result" : @(RESULT_FALSE), @"err_msg" : msg }; } } } // 压缩目录 NSString *zip = [self _zipDir:upDir]; // 删除目录 [fm removeItemAtPath:upDir error:nil]; NSRange start = [zip rangeOfString:@"upload"]; zipF = [zip substringFromIndex:start.location]; Unlock(); } // 创建Task NSMutableDictionary *task = [@{ @"order" : orderId, @"action" : title, @"name" : title, @"time" : time, @"url" : URL_UPLOAD, @"params" : mParams } mutableCopy]; if (zipF) { [task setObject:zipF forKey:@"file"]; } else { [task setObject:@(YES) forKey:@"noFile"]; } dispatch_async(dispatch_get_main_queue(), ^{ // 提交Task AppDelegate *appDelegate = (AppDelegate *)[UIApplication sharedApplication].delegate; [appDelegate.uploadManager addTask:task]; }); // 删除Edit文件 [self deleteEditJsonFileForOrder:orderId withActionIndex:idx]; // 判断是否完成order 所有操作 BOOL finish = [self isLastActionForOrder:orderId index:idx]; // 将order从Processing中删除 // 加载Home NSMutableDictionary *home = [[self requestOfflineHome] mutableCopy]; if (home) { NSMutableArray *sections = [[home objectForKey:@"sections"] mutableCopy]; if (sections) { __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 *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; } }]; if (finish) { [orders removeObject:curOrder]; if (orders.count > 0) { [section setObject:orders forKey:@"orders"]; // 重新生成section [sections replaceObjectAtIndex:i withObject:section]; } else { rmSection = [sections objectAtIndex:i]; } } else { [curOrder setValue:@(NO) forKey:@"backendFlag"]; [curOrder setValue:[self statusTitleForActionIndex:idx] forKey:@"title"]; } break; } } if (rmSection) { [sections removeObject:rmSection]; } // 重新生成sections [home setObject:sections forKey:@"sections"]; } // 更新Home文件 [self updateHome:home]; } // 更新Action [self updateLastAction:idx forOrder:orderId]; return @{ @"result" : @(RESULT_TRUE) }; } @end